5dedf56cf5369f1ca91753ebaa51944f40916960
1 # -*- coding: utf-8 -*-
4 Authenticator is responsible for authenticating the users,
5 create the tokens unscoped and scoped, retrieve the role
6 list inside the projects that they are inserted
9 __author__
= "Eduardo Sousa <eduardosousa@av.it.pt>"
10 __date__
= "$27-jul-2018 23:59:59$"
15 from base64
import standard_b64decode
16 from http
import HTTPStatus
18 from authconn_keystone
import AuthconnKeystone
19 from engine
import EngineException
22 class AuthException(Exception):
23 def __init__(self
, message
, http_code
=HTTPStatus
.UNAUTHORIZED
):
24 self
.http_code
= http_code
25 Exception.__init
__(self
, message
)
30 This class should hold all the mechanisms for User Authentication and
31 Authorization. Initially it should support Openstack Keystone as a
32 backend through a plugin model where more backends can be added and a
33 RBAC model to manage permissions on operations.
36 def __init__(self
, engine
):
38 Authenticator initializer. Setup the initial state of the object,
39 while it waits for the config dictionary and database initialization.
41 Note: engine is only here until all the calls can to it can be replaced.
43 :param engine: reference to engine object used.
52 self
.logger
= logging
.getLogger("nbi.authenticator")
54 def start(self
, config
):
56 Method to configure the Authenticator object. This method should be called
57 after object creation. It is responsible by initializing the selected backend,
58 as well as the initialization of the database connection.
60 :param config: dictionary containing the relevant parameters for this object.
66 if config
["authenticator"]["backend"] == "keystone":
67 self
.backend
= AuthconnKeystone(self
.config
["authenticator"])
70 # TODO: Implement database initialization
71 # NOTE: Database needed to store the mappings
72 except Exception as e
:
73 raise AuthException(str(e
))
77 def init_db(self
, target_version
='1.0'):
79 Check if the database has been initialized. If not, create the required tables
80 and insert the predefined mappings between roles and permissions.
82 :param target_version: schema version that should be present in the database.
83 :return: None if OK, exception if error or version is different.
91 # 1. Get token Authorization bearer
92 auth
= cherrypy
.request
.headers
.get("Authorization")
94 auth_list
= auth
.split(" ")
95 if auth_list
[0].lower() == "bearer":
97 elif auth_list
[0].lower() == "basic":
98 user_passwd64
= auth_list
[-1]
100 if cherrypy
.session
.get("Authorization"):
101 # 2. Try using session before request a new token. If not, basic authentication will generate
102 token
= cherrypy
.session
.get("Authorization")
103 if token
== "logout":
104 token
= None # force Unauthorized response to insert user pasword again
105 elif user_passwd64
and cherrypy
.request
.config
.get("auth.allow_basic_authentication"):
106 # 3. Get new token from user password
110 user_passwd
= standard_b64decode(user_passwd64
).decode()
111 user
, _
, passwd
= user_passwd
.partition(":")
114 outdata
= self
.engine
.new_token(None, {"username": user
, "password": passwd
})
115 token
= outdata
["id"]
116 cherrypy
.session
['Authorization'] = token
117 # 4. Get token from cookie
119 # auth_cookie = cherrypy.request.cookie.get("Authorization")
121 # token = auth_cookie.value
122 return self
.engine
.authorize(token
)
123 except EngineException
as e
:
124 if cherrypy
.session
.get('Authorization'):
125 del cherrypy
.session
['Authorization']
126 cherrypy
.response
.headers
["WWW-Authenticate"] = 'Bearer realm="{}"'.format(e
)
127 raise AuthException(str(e
))
129 def new_token(self
, session
, indata
, remote
):
130 return self
.engine
.new_token(session
, indata
, remote
)
132 def get_token_list(self
, session
):
133 return self
.engine
.get_token_list(session
)
135 def get_token(self
, session
, token_id
):
136 return self
.engine
.get_token(session
, token_id
)
138 def del_token(self
, token_id
):
139 return self
.engine
.del_token(token_id
)