...
Method | Description | Parameter | Example | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Verify Access Token | Allows a client to verify an access token not directly requested from the oAuth2 server. |
|
|
The following examples show concrete use-cases where the session login and oAuth2 mechanisms are used within the Flarecast infrastructure.
...
By the above section we described the workflows of a session login and oAuth2 authentification. The concrete implementation is given by two Flask-addons which are build on the top of our web servers used within the Flarecast infrastructure.
Python Package | Description | URL / Documentation |
---|---|---|
flask-login | ||
flask-oauthlib |
,
which file contains what? parametrization
(0.4.0) | User session management support for Flask. | https://flask-login.readthedocs.io/en/latest/ |
flask-oauthlib (0.9.3) | oAuth1/oAuth2 client and provider support for Flask. Build with the oauthlib. | https://flask-oauthlib.readthedocs.io/en/latest/ |
The integration of the two packages can be found within the python-base image. Hereby, the following files are involved:
flask_login:
File
Description Highlights /flarecast/service/flarecast_service.py Wrapper class for the Connexion framework (including Flask & Swagger). Code Block language py collapse true # Initialize flask_login login_manager = flask_login.LoginManager() login_manager.init_app(app.app) # set login view which is used for unauthorized # users which access protected ressources login_manager.login_view = "/login" # callback used for reloading a user based on # the request's session information @login_manager.user_loader def load_user(user_id): with AdminDAO() as ctx: return ctx.get_user_by_id(user_id) return None
/flarecast/service/models.py Module which holds all models required by flask_login and flask_oauthlib. Code Block language py collapse true # class which holds all user related information class User(UserMixin): def __init__( self, id, name, password_hash, is_authenticated=False, is_active=False, is_anonymous=True ): self.id = id self.name = name self.password_hash = password_hash self.authenticated = is_authenticated self.active = is_active self.anonymous = is_anonymous def set_password_hash(self, password): self.password_hash = md5(password+self.name).hexdigest() def is_correct_password(self, password): return self.password_hash == md5(password + self.name).hexdigest() # ...
/flarecast/service/users/views.py Blueprint of the user login and logout pages. Code Block language py collapse true @blueprint.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': form = LoginForm(request.form) with AdminDAO() as ctx: # load user from database user = ctx.get_user_by_name(form.username.data) if ( user is not None and user.is_correct_password(form.password.data) ): # set flag as user was authenticated user.set_authenticated(True) with AdminDAO() as ctx: ctx.update_user_is_authenticated( user.id, user.is_authenticated ) # create session cookies with user and session IDs login_user(user) return redirect(redirect_url('ui')) return render_template('login.html', form=form)
/flarecast/service/admin_dao.py The data access object (DAO) which mapps requests and database cursers to database queries and python objects. Code Block language py collapse true # ...
flask_oauthlib
File
Description Highlights /flarecast/service/flarecast_service.py Wrapper class for the Connexion framework (including Flask & Swagger). Code Block language py collapse true # Initialize provider from flask_oauthlib oauth = FlarecastProvider() oauth.init_app(app.app) app.app.config.update( # set default error page OAUTH2_PROVIDER_ERROR_ENDPOINT='/error', # set expire time in seconds for access tokens (86400s = 1d) OAUTH2_PROVIDER_TOKEN_EXPIRES_IN=86400 )
/flarecast/service/models.py Module which holds all models required by flask_login and flask_oauthlib. Code Block language py collapse true # ...
/flarecast/service/oauth/views.py Blueprint for authorize, access, revoke and validate access tokens. Each route is wrapped by a function provided by flask_oauthlib which implements the authorization flow. Code Block language py collapse true # authorization route where the end-user grant's an access token for a client @blueprint.route('/oauth/authorize', methods=['GET', 'POST']) @flask_login.login_required # route req. session login @oauth.authorize_handler def authorize(*args, **kwargs): if request.method == 'GET': with AdminDAO() as ctx: client = ctx.get_client_by_id(int(kwargs.get('client_id'))) return render_template('confirm.html', **kwargs) confirm = request.form.get('confirm', 'no') return confirm == 'yes' # request route for access tokens @blueprint.route('/oauth/token', methods=['POST']) @oauth.token_handler def access_token(): return {'version': '1.0.0'} # route for revoke access tokens @blueprint.route('/oauth/revoke', methods=['POST']) @oauth.revoke_handler def revoke_token(): pass # route for verifying access tokens @blueprint.route('/oauth/tokeninfo') def get_tokeninfo(): if "access_token" in request.args: with AdminDAO() as ctx: bearer_token = ctx.get_bearer_token_by_access_token( request.args.get("access_token") ) if bearer_token is not None: return jsonify( {'uid': bearer_token.id, 'scope': bearer_token.scopes} ) return 'No such token', 401
/flarecast/service/admin_dao.py The data access object (DAO) which mapps requests and database cursers to database queries and python objects. Code Block language py collapse true # ...
A last missing fragment is the database schema which persistantly stores the users, clients and tokens refered above:
The central entity is the user which, by assumption, owns ressources he grants access to. A client can then define reliable clients and administrate there grant as well as bearer (access) tokens. This workflow however is not defined by the above database schema nor oAuth2. Flarecast do not provide corresponding functionalities for managing users at the moment, so each user has to be manually added to the database. Furthermore, a fine-grained user management system may add some user roles which could then be mapped to specific scopes. An example may look like:
User Role | Resource Scope | Example |
---|---|---|
Reader | read | Access to protected routes for querying configurations of prediction algorithms. |
Writer | write | Access to protected routes for adding prediction data to existing predictions. |
Moderator | read, write | Full (read and write) access to the prediction service. |
Administrator | read, write, execute | Full access to the workflow management service, including protected routes for running and stopping Docker containers. |
login_manager = flask_login.LoginManager()
login_manager.init_app(app.app)
login_manager.login_view = "users.login"
@login_manager.user_loader
def load_user(user_id):
with AdminDAO() as ctx:
return ctx.get_user_by_id(user_id)
return None