Coverage for mcpgateway / plugins / framework / hooks / http.py: 98%

57 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-02-11 07:10 +0000

1# -*- coding: utf-8 -*- 

2"""Location: ./mcpgateway/plugins/framework/models/http.py 

3Copyright 2025 

4SPDX-License-Identifier: Apache-2.0 

5Authors: Teryl Taylor 

6 

7Pydantic models for http hooks and payloads. 

8""" 

9 

10# Standard 

11from enum import Enum 

12 

13# Third-Party 

14from pydantic import RootModel 

15 

16# First-Party 

17from mcpgateway.plugins.framework.models import PluginPayload, PluginResult 

18 

19 

20class HttpHeaderPayload(RootModel[dict[str, str]], PluginPayload): 

21 """An HTTP dictionary of headers used in the pre/post HTTP forwarding hooks.""" 

22 

23 def __iter__(self): # type: ignore[no-untyped-def] 

24 """Custom iterator function to override root attribute. 

25 

26 Returns: 

27 A custom iterator for header dictionary. 

28 """ 

29 return iter(self.root) 

30 

31 def __getitem__(self, item: str) -> str: 

32 """Custom getitem function to override root attribute. 

33 

34 Args: 

35 item: The http header key. 

36 

37 Returns: 

38 A custom accesser for the header dictionary. 

39 """ 

40 return self.root[item] 

41 

42 def __setitem__(self, key: str, value: str) -> None: 

43 """Custom setitem function to override root attribute. 

44 

45 Args: 

46 key: The http header key. 

47 value: The http header value to be set. 

48 """ 

49 self.root[key] = value 

50 

51 def __len__(self) -> int: 

52 """Custom len function to override root attribute. 

53 

54 Returns: 

55 The len of the header dictionary. 

56 """ 

57 return len(self.root) 

58 

59 

60HttpHeaderPayloadResult = PluginResult[HttpHeaderPayload] 

61 

62 

63class HttpHookType(str, Enum): 

64 """Hook types for HTTP request processing and authentication. 

65 

66 These hooks allow plugins to: 

67 1. Transform request headers before processing (middleware layer) 

68 2. Implement custom user authentication systems (auth layer) 

69 3. Check and grant permissions (RBAC layer) 

70 4. Process responses after request completion (middleware layer) 

71 """ 

72 

73 HTTP_PRE_REQUEST = "http_pre_request" 

74 HTTP_POST_REQUEST = "http_post_request" 

75 HTTP_AUTH_RESOLVE_USER = "http_auth_resolve_user" 

76 HTTP_AUTH_CHECK_PERMISSION = "http_auth_check_permission" 

77 

78 

79class HttpPreRequestPayload(PluginPayload): 

80 """Payload for HTTP pre-request hook (middleware layer). 

81 

82 This payload contains immutable request metadata and a copy of headers 

83 that plugins can inspect. Invoked before any authentication processing. 

84 Plugins return only modified headers via PluginResult[HttpHeaderPayload]. 

85 

86 Attributes: 

87 path: HTTP path being requested. 

88 method: HTTP method (GET, POST, etc.). 

89 client_host: Client IP address (if available). 

90 client_port: Client port (if available). 

91 headers: Copy of HTTP headers that plugins can inspect and modify. 

92 """ 

93 

94 path: str 

95 method: str 

96 client_host: str | None = None 

97 client_port: int | None = None 

98 headers: HttpHeaderPayload 

99 

100 

101class HttpPostRequestPayload(HttpPreRequestPayload): 

102 """Payload for HTTP post-request hook (middleware layer). 

103 

104 Extends HttpPreRequestPayload with response information. 

105 Invoked after request processing is complete. 

106 Plugins can inspect response headers and status codes. 

107 

108 Attributes: 

109 response_headers: Response headers from the request (if available). 

110 status_code: HTTP status code from the response (if available). 

111 """ 

112 

113 response_headers: HttpHeaderPayload | None = None 

114 status_code: int | None = None 

115 

116 

117class HttpAuthResolveUserPayload(PluginPayload): 

118 """Payload for custom user authentication hook (auth layer). 

119 

120 Invoked inside get_current_user() to allow plugins to provide 

121 custom authentication mechanisms (LDAP, mTLS, external auth, etc.). 

122 Plugins return an authenticated user via PluginResult[dict]. 

123 

124 Attributes: 

125 credentials: The HTTP authorization credentials from bearer_scheme (if present). 

126 headers: Full request headers for custom auth extraction. 

127 client_host: Client IP address (if available). 

128 client_port: Client port (if available). 

129 """ 

130 

131 credentials: dict | None = None # HTTPAuthorizationCredentials serialized 

132 headers: HttpHeaderPayload 

133 client_host: str | None = None 

134 client_port: int | None = None 

135 

136 

137class HttpAuthCheckPermissionPayload(PluginPayload): 

138 """Payload for permission checking hook (RBAC layer). 

139 

140 Invoked before RBAC permission checks to allow plugins to: 

141 - Grant/deny permissions based on custom logic (e.g., token-based auth) 

142 - Bypass RBAC for certain authentication methods 

143 - Add additional permission checks (e.g., time-based, IP-based) 

144 - Implement custom authorization logic 

145 

146 Attributes: 

147 user_email: Email of the authenticated user 

148 permission: Required permission being checked (e.g., "tools.read", "servers.write") 

149 resource_type: Type of resource being accessed (e.g., "tool", "server", "prompt") 

150 team_id: Team context for the permission check (if applicable) 

151 is_admin: Whether the user has admin privileges 

152 auth_method: Authentication method used (e.g., "simple_token", "jwt", "oauth") 

153 client_host: Client IP address for IP-based permission checks 

154 user_agent: User agent string for device-based permission checks 

155 """ 

156 

157 user_email: str 

158 permission: str 

159 resource_type: str | None = None 

160 team_id: str | None = None 

161 is_admin: bool = False 

162 auth_method: str | None = None 

163 client_host: str | None = None 

164 user_agent: str | None = None 

165 

166 

167class HttpAuthCheckPermissionResultPayload(PluginPayload): 

168 """Result payload for permission checking hook. 

169 

170 Plugins return this to indicate whether permission should be granted. 

171 

172 Attributes: 

173 granted: Whether permission is granted (True) or denied (False) 

174 reason: Optional reason for the decision (for logging/auditing) 

175 """ 

176 

177 granted: bool 

178 reason: str | None = None 

179 

180 

181# Type aliases for hook results 

182HttpPreRequestResult = PluginResult[HttpHeaderPayload] 

183HttpPostRequestResult = PluginResult[HttpHeaderPayload] 

184HttpAuthResolveUserResult = PluginResult[dict] # Returns user dict (EmailUser serialized) 

185HttpAuthCheckPermissionResult = PluginResult[HttpAuthCheckPermissionResultPayload] 

186 

187 

188def _register_http_auth_hooks() -> None: 

189 """Register HTTP authentication and request hooks in the global registry. 

190 

191 This is called lazily to avoid circular import issues. 

192 Registers four hook types: 

193 - HTTP_PRE_REQUEST: Transform headers before authentication (middleware) 

194 - HTTP_POST_REQUEST: Inspect response after request completion (middleware) 

195 - HTTP_AUTH_RESOLVE_USER: Custom user authentication (auth layer) 

196 - HTTP_AUTH_CHECK_PERMISSION: Custom permission checking (RBAC layer) 

197 """ 

198 # Import here to avoid circular dependency at module load time 

199 # First-Party 

200 from mcpgateway.plugins.framework.hooks.registry import get_hook_registry # pylint: disable=import-outside-toplevel 

201 

202 registry = get_hook_registry() 

203 

204 # Only register if not already registered (idempotent) 

205 if not registry.is_registered(HttpHookType.HTTP_PRE_REQUEST): 205 ↛ exitline 205 didn't return from function '_register_http_auth_hooks' because the condition on line 205 was always true

206 registry.register_hook(HttpHookType.HTTP_PRE_REQUEST, HttpPreRequestPayload, HttpPreRequestResult) 

207 registry.register_hook(HttpHookType.HTTP_POST_REQUEST, HttpPostRequestPayload, HttpPostRequestResult) 

208 registry.register_hook(HttpHookType.HTTP_AUTH_RESOLVE_USER, HttpAuthResolveUserPayload, HttpAuthResolveUserResult) 

209 registry.register_hook(HttpHookType.HTTP_AUTH_CHECK_PERMISSION, HttpAuthCheckPermissionPayload, HttpAuthCheckPermissionResult) 

210 

211 

212_register_http_auth_hooks()