|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +
|
| 4 | + mslib.mscolab.blueprints.auth.auth |
| 5 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 6 | +
|
| 7 | + Auth Blueprint for server for mscolab module |
| 8 | +
|
| 9 | + This file is part of MSS. |
| 10 | +
|
| 11 | + :copyright: Copyright 2019 Shivashis Padhi |
| 12 | + :copyright: Copyright 2019-2026 by the MSS team, see AUTHORS. |
| 13 | + :license: APACHE-2.0, see LICENSE for details. |
| 14 | +
|
| 15 | + Licensed under the Apache License, Version 2.0 (the "License"); |
| 16 | + you may not use this file except in compliance with the License. |
| 17 | + You may obtain a copy of the License at |
| 18 | +
|
| 19 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 20 | +
|
| 21 | + Unless required by applicable law or agreed to in writing, software |
| 22 | + distributed under the License is distributed on an "AS IS" BASIS, |
| 23 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 24 | + See the License for the specific language governing permissions and |
| 25 | + limitations under the License. |
| 26 | +""" |
| 27 | + |
1 | 28 | import datetime |
2 | | -import functools |
3 | 29 | import json |
4 | 30 | import logging |
5 | 31 | import secrets |
6 | 32 |
|
7 | | -import sqlalchemy |
8 | | -import email_validator |
9 | | -# Todo use the name email_validator |
10 | | -from email_validator import validate_email |
11 | | -from flask import Blueprint, request, url_for, render_template, jsonify, flash, redirect, abort, g |
| 33 | +from flask import Blueprint, request, url_for, render_template, jsonify, flash, redirect |
12 | 34 | from flask_httpauth import HTTPBasicAuth |
13 | | -from flask_mail import Message |
14 | 35 | from flask.wrappers import Response |
15 | | -from itsdangerous import URLSafeTimedSerializer, BadSignature |
16 | 36 | from saml2 import BINDING_HTTP_REDIRECT, BINDING_HTTP_POST |
17 | 37 | from saml2.metadata import create_metadata_string |
18 | 38 |
|
|
21 | 41 | from mslib.mscolab.models import User |
22 | 42 | from mslib.mscolab.app import APP |
23 | 43 | from mslib.utils import conditional_decorator |
24 | | - |
25 | | - |
26 | | -def check_login(emailid, password): |
27 | | - try: |
28 | | - user = User.query.filter_by(emailid=str(emailid)).first() |
29 | | - except sqlalchemy.exc.OperationalError as ex: |
30 | | - logging.debug("Problem in the database (%ex), likely version client different", ex) |
31 | | - return False |
32 | | - if user is not None: |
33 | | - if APP.config['MAIL_ENABLED']: |
34 | | - if user.confirmed: |
35 | | - if user.verify_password(password): |
36 | | - return user |
37 | | - else: |
38 | | - if user.verify_password(password): |
39 | | - return user |
40 | | - return False |
41 | | - |
42 | | - |
43 | | -def register_user(email, password, username, fullname): |
44 | | - if len(str(email.strip())) == 0 or len(str(username.strip())) == 0: |
45 | | - return {"success": False, "message": "Your username or email cannot be empty"} |
46 | | - is_valid_username = True if username.find("@") == -1 else False |
47 | | - try: |
48 | | - # ToDo verify what changed for check_deliverability |
49 | | - validate_email(email, check_deliverability=APP.config['MAIL_ENABLED']) |
50 | | - except (email_validator.exceptions.EmailSyntaxError): |
51 | | - return {"success": False, "message": "Your email ID is not valid!"} |
52 | | - if not is_valid_username: |
53 | | - return {"success": False, "message": "Your username cannot contain @ symbol!"} |
54 | | - user_exists = User.query.filter_by(emailid=str(email)).first() |
55 | | - if user_exists: |
56 | | - return {"success": False, "message": "This email ID is already taken!"} |
57 | | - user_exists = User.query.filter_by(username=str(username)).first() |
58 | | - if user_exists: |
59 | | - return {"success": False, "message": "This username is already registered"} |
60 | | - from mslib.mscolab.server import getConfig |
61 | | - fm = getConfig()[3] |
62 | | - user = User(email, username, password, fullname) |
63 | | - result = fm.modify_user(user, action="create") |
64 | | - return {"success": result} |
65 | | - |
66 | | - |
67 | | -def generate_confirmation_token(email): |
68 | | - serializer = URLSafeTimedSerializer(APP.config['SECRET_KEY']) |
69 | | - return serializer.dumps(email, salt=APP.config['SECURITY_PASSWORD_SALT']) |
70 | | - |
71 | | - |
72 | | -def send_email(to, subject, template): |
73 | | - if APP.config['MAIL_DEFAULT_SENDER'] is not None: |
74 | | - msg = Message( |
75 | | - subject, |
76 | | - recipients=[to], |
77 | | - html=template, |
78 | | - sender=APP.config['MAIL_DEFAULT_SENDER'] |
79 | | - ) |
80 | | - try: |
81 | | - from mslib.mscolab.server import getConfig |
82 | | - mail = getConfig()[4] |
83 | | - mail.send(msg) |
84 | | - except IOError: |
85 | | - logging.error("Can't send email to %s", to) |
86 | | - else: |
87 | | - logging.debug("setup user verification by email") |
88 | | - |
89 | | - |
90 | | -def confirm_token(token, expiration=3600): |
91 | | - serializer = URLSafeTimedSerializer(APP.config['SECRET_KEY']) |
92 | | - try: |
93 | | - email = serializer.loads( |
94 | | - token, |
95 | | - salt=APP.config['SECURITY_PASSWORD_SALT'], |
96 | | - max_age=expiration |
97 | | - ) |
98 | | - except (IOError, BadSignature): |
99 | | - return False |
100 | | - return email |
101 | | - |
102 | | - |
103 | | -def get_idp_entity_id(selected_idp): |
104 | | - """ |
105 | | - Finds the entity_id from the configured IDPs |
106 | | - :return: the entity_id of the idp or None |
107 | | - """ |
108 | | - for config in setup_saml2_backend.CONFIGURED_IDPS: |
109 | | - if selected_idp == config['idp_identity_name']: |
110 | | - idps = config['idp_data']['saml2client'].metadata.identity_providers() |
111 | | - only_idp = idps[0] |
112 | | - entity_id = only_idp |
113 | | - return entity_id |
114 | | - return None |
115 | | - |
116 | | - |
117 | | -def create_or_update_idp_user(email, username, token, authentication_backend): |
118 | | - """ |
119 | | - Creates or updates an idp user in the system based on the provided email, |
120 | | - username, token, and authentication backend. |
121 | | - :param email: idp users email |
122 | | - :param username: idp users username |
123 | | - :param token: authentication token |
124 | | - :param authentication_backend: authenticated identity providers name |
125 | | - :return: bool : query success or not |
126 | | - """ |
127 | | - from mslib.mscolab.server import getConfig |
128 | | - fm = getConfig()[3] |
129 | | - user = User.query.filter_by(emailid=email).first() |
130 | | - if not user: |
131 | | - # using an IDP for a new account/profile, e-mail is already verified by the IDP |
132 | | - confirm_time = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(seconds=1) |
133 | | - user = User(email, username, password=token, confirmed=True, confirmed_on=confirm_time, |
134 | | - authentication_backend=authentication_backend) |
135 | | - result = fm.modify_user(user, action="create") |
136 | | - else: |
137 | | - user.authentication_backend = authentication_backend |
138 | | - user.hash_password(token) |
139 | | - result = fm.modify_user(user, action="update_idp_user") |
140 | | - return result |
141 | | - |
142 | | - |
143 | | -def verify_user(func): |
144 | | - @functools.wraps(func) |
145 | | - def wrapper(*args, **kwargs): |
146 | | - try: |
147 | | - user = User.verify_auth_token(request.args.get('token', request.form.get('token', False))) |
148 | | - except TypeError: |
149 | | - logging.debug("no token in request form") |
150 | | - abort(404) |
151 | | - if not user: |
152 | | - return "False" |
153 | | - else: |
154 | | - # saving user details in flask.g |
155 | | - if APP.config['MAIL_ENABLED']: |
156 | | - if user.confirmed: |
157 | | - g.user = user |
158 | | - return func(*args, **kwargs) |
159 | | - else: |
160 | | - return "False" |
161 | | - else: |
162 | | - g.user = user |
163 | | - return func(*args, **kwargs) |
164 | | - return wrapper |
165 | | - |
| 44 | +from mslib.utils.auth import check_login, register_user, generate_confirmation_token, send_email, confirm_token, \ |
| 45 | + get_idp_entity_id, create_or_update_idp_user |
166 | 46 |
|
167 | 47 | AUTH_BP = Blueprint('auth', __name__) |
168 | 48 | auth_basic_auth = HTTPBasicAuth() |
|
0 commit comments