1 # Copyright (C) 2022 Wind River Systems, Inc.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
16 from flask_restx._http import HTTPStatus
17 from werkzeug.wrappers import Request, Response
19 from o2common.authmw.authprov import auth_definer
20 from o2common.authmw.exceptions import AuthRequiredExp
21 from o2common.authmw.exceptions import AuthFailureExp
22 from o2common.helper import o2logging
24 logger = o2logging.get_logger(__name__)
27 class AuthProblemDetails():
28 def __init__(self, code: int, detail: str, path: str,
29 title=None, instance=None
34 self.title = title if title is not None else self.getTitle(code)
35 self.instance = instance if instance is not None else []
37 def getTitle(self, code):
38 return HTTPStatus(code).phrase
43 if key == 'ns' or key.startswith('__') or \
44 callable(getattr(self, key)):
47 details[key] = getattr(self, key)
48 return json.dumps(details, indent=True)
51 def _response_wrapper(environ, start_response, header, detail):
52 res = Response(headers=header,
53 mimetype='application/json', status=401, response=detail)
54 return res(environ, start_response)
57 def _internal_err_response_wrapper(environ, start_response, detail):
58 res = Response(mimetype='application/json', status=500, response=detail)
59 return res(environ, start_response)
62 class authmiddleware():
67 def __init__(self, app):
70 def __call__(self, environ, start_response):
71 logger.debug(__name__ + 'authentication middleware')
72 req = Request(environ, populate_request=True, shallow=True)
75 auth_header = req.headers.get('Authorization', None)
77 auth_token = auth_header.split(" ")[1]
79 ad = auth_definer('oauth')
80 # invoke underlying auth mdw to make k8s/keystone api
81 ret = ad.authenticate(auth_token)
84 "auth success with oauth token: " + auth_token)
86 return self.app(environ, start_response)
87 except Exception as ex:
89 'Internal exception happend \
90 ed {}'.format(str(ex)), exc_info=True)
91 prb = AuthProblemDetails(
92 500, 'Internal error.', req.path)
94 _internal_err_response_wrapper(
96 start_response, prb.serialize())
99 'Bearer realm="Authentication Failed"')
101 raise AuthRequiredExp('Bearer realm="Authentication Required"')
102 except AuthRequiredExp as ex:
103 prb = AuthProblemDetails(401, ex.value, req.path)
104 return _response_wrapper(environ, start_response,
105 ex.dictize(), prb.serialize())
106 except AuthFailureExp as ex:
107 prb = AuthProblemDetails(401, ex.value, req.path)
108 return _response_wrapper(environ, start_response,
109 ex.dictize(), prb.serialize())
110 except Exception as ex:
112 logger.error('Internal exception happended {}'.format(
113 str(ex)), exc_info=True)
114 prb = AuthProblemDetails(500, 'Internal error.', req.path)
116 _internal_err_response_wrapper(
117 environ, start_response, prb.serialize())
119 logger.debug('Auth token missing or not obtained.')
120 ex = AuthRequiredExp('Bearer realm="Authentication Required"')
121 prb = AuthProblemDetails(401, ex.value, req.path)
122 return _response_wrapper(environ, start_response,
123 ex.dictize(), prb.serialize())