Coverage for manila/api/middleware/auth.py: 76%

92 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright 2010 OpenStack LLC. 

2# All Rights Reserved. 

3# 

4# Licensed under the Apache License, Version 2.0 (the "License"); you may 

5# not use this file except in compliance with the License. You may obtain 

6# a copy of the License at 

7# 

8# http://www.apache.org/licenses/LICENSE-2.0 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

13# License for the specific language governing permissions and limitations 

14# under the License. 

15""" 

16Common Auth Middleware. 

17 

18""" 

19import os 

20 

21from oslo_config import cfg 

22from oslo_log import log 

23from oslo_serialization import jsonutils 

24import webob.dec 

25import webob.exc 

26 

27from manila.api.openstack import wsgi 

28from manila import context 

29from manila.i18n import _ 

30from manila.wsgi import common as base_wsgi 

31 

32use_forwarded_for_opt = cfg.BoolOpt( 

33 'use_forwarded_for', 

34 default=False, 

35 deprecated_for_removal=True, 

36 deprecated_reason='This feature is duplicate of the HTTPProxyToWSGI ' 

37 'middleware of oslo.middleware.', 

38 deprecated_since='Zed', 

39 help='Treat X-Forwarded-For as the canonical remote address. ' 

40 'Only enable this if you have a sanitizing proxy.') 

41 

42CONF = cfg.CONF 

43CONF.register_opt(use_forwarded_for_opt) 

44LOG = log.getLogger(__name__) 

45 

46 

47def pipeline_factory(loader, global_conf, **local_conf): 

48 """A paste pipeline replica that keys off of auth_strategy.""" 

49 pipeline = local_conf[CONF.auth_strategy] 

50 if not CONF.api_rate_limit: 50 ↛ 51line 50 didn't jump to line 51 because the condition on line 50 was never true

51 limit_name = CONF.auth_strategy + '_nolimit' 

52 pipeline = local_conf.get(limit_name, pipeline) 

53 pipeline = pipeline.split() 

54 filters = [loader.get_filter(n) for n in pipeline[:-1]] 

55 app = loader.get_app(pipeline[-1]) 

56 filters.reverse() 

57 for filter in filters: 

58 app = filter(app) 

59 return app 

60 

61 

62class InjectContext(base_wsgi.Middleware): 

63 """Add a 'manila.context' to WSGI environ.""" 

64 

65 def __init__(self, context, *args, **kwargs): 

66 self.context = context 

67 super(InjectContext, self).__init__(*args, **kwargs) 

68 

69 @webob.dec.wsgify(RequestClass=base_wsgi.Request) 

70 def __call__(self, req): 

71 req.environ['manila.context'] = self.context 

72 return self.application 

73 

74 

75class ManilaKeystoneContext(base_wsgi.Middleware): 

76 """Make a request context from keystone headers.""" 

77 

78 @webob.dec.wsgify(RequestClass=base_wsgi.Request) 

79 def __call__(self, req): 

80 # Build a context, including the auth_token... 

81 remote_address = req.remote_addr 

82 if CONF.use_forwarded_for: 82 ↛ 83line 82 didn't jump to line 83 because the condition on line 82 was never true

83 remote_address = req.headers.get('X-Forwarded-For', remote_address) 

84 

85 service_catalog = None 

86 if req.headers.get('X_SERVICE_CATALOG') is not None: 86 ↛ 87line 86 didn't jump to line 87 because the condition on line 86 was never true

87 try: 

88 catalog_header = req.headers.get('X_SERVICE_CATALOG') 

89 service_catalog = jsonutils.loads(catalog_header) 

90 except ValueError: 

91 raise webob.exc.HTTPInternalServerError( 

92 _('Invalid service catalog json.')) 

93 

94 ctx = context.RequestContext.from_environ( 

95 req.environ, 

96 remote_address=remote_address, 

97 service_catalog=service_catalog) 

98 

99 if ctx.user_id is None: 

100 LOG.debug("Neither X_USER_ID nor X_USER found in request") 

101 return webob.exc.HTTPUnauthorized() 

102 

103 if req.environ.get('X_PROJECT_DOMAIN_ID'): 103 ↛ 104line 103 didn't jump to line 104 because the condition on line 103 was never true

104 ctx.project_domain_id = req.environ['X_PROJECT_DOMAIN_ID'] 

105 

106 if req.environ.get('X_PROJECT_DOMAIN_NAME'): 106 ↛ 107line 106 didn't jump to line 107 because the condition on line 106 was never true

107 ctx.project_domain_name = req.environ['X_PROJECT_DOMAIN_NAME'] 

108 

109 if req.environ.get('X_USER_DOMAIN_ID'): 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true

110 ctx.user_domain_id = req.environ['X_USER_DOMAIN_ID'] 

111 

112 if req.environ.get('X_USER_DOMAIN_NAME'): 112 ↛ 113line 112 didn't jump to line 113 because the condition on line 112 was never true

113 ctx.user_domain_name = req.environ['X_USER_DOMAIN_NAME'] 

114 

115 req.environ['manila.context'] = ctx 

116 return self.application 

117 

118 

119class NoAuthMiddlewareBase(base_wsgi.Middleware): 

120 """Return a fake token if one isn't specified.""" 

121 

122 def base_call(self, req, project_id_in_path=False): 

123 if 'X-Auth-Token' not in req.headers: 

124 user_id = req.headers.get('X-Auth-User', 'admin') 

125 project_id = req.headers.get('X-Auth-Project-Id', 'admin') 

126 if project_id_in_path: 126 ↛ 129line 126 didn't jump to line 129 because the condition on line 126 was always true

127 os_url = os.path.join(req.url.rstrip('/'), project_id) 

128 else: 

129 os_url = req.url.rstrip('/') 

130 res = webob.Response() 

131 # NOTE(vish): This is expecting and returning Auth(1.1), whereas 

132 # keystone uses 2.0 auth. We should probably allow 

133 # 2.0 auth here as well. 

134 res.headers['X-Auth-Token'] = '%s:%s' % (user_id, project_id) 

135 res.headers['X-Server-Management-Url'] = os_url 

136 res.content_type = 'text/plain' 

137 res.status = '204' 

138 return res 

139 

140 token = req.headers['X-Auth-Token'] 

141 user_id, _sep, project_id = token.partition(':') 

142 project_id = project_id or user_id 

143 remote_address = getattr(req, 'remote_addr', '127.0.0.1') 

144 if CONF.use_forwarded_for: 144 ↛ 145line 144 didn't jump to line 145 because the condition on line 144 was never true

145 remote_address = req.headers.get('X-Forwarded-For', remote_address) 

146 ctx = context.RequestContext(user_id, 

147 project_id, 

148 is_admin=True, 

149 remote_address=remote_address) 

150 

151 req.environ['manila.context'] = ctx 

152 return self.application 

153 

154 

155class NoAuthMiddleware(NoAuthMiddlewareBase): 

156 """Return a fake token if one isn't specified. 

157 

158 Sets project_id in URLs. 

159 """ 

160 

161 @webob.dec.wsgify(RequestClass=wsgi.Request) 

162 def __call__(self, req): 

163 return self.base_call(req, project_id_in_path=True) 

164 

165 

166class NoAuthMiddlewarev2_60(NoAuthMiddlewareBase): 

167 """Return a fake token if one isn't specified. 

168 

169 Does not set project_id in URLs. 

170 """ 

171 @webob.dec.wsgify(RequestClass=wsgi.Request) 

172 def __call__(self, req): 

173 return self.base_call(req)