def test_access_token_with_fetch_token(self): app = Flask(__name__) app.secret_key = '!' oauth = OAuth() token = get_bearer_token() oauth.init_app(app, fetch_token=lambda name: token) client = oauth.register('dev', client_id='dev', client_secret='dev', api_base_url='https://i.b/api', access_token_url='https://i.b/token', authorize_url='https://i.b/authorize') def fake_send(sess, req, **kwargs): auth = req.headers['Authorization'] self.assertEqual(auth, 'Bearer {}'.format(token['access_token'])) resp = mock.MagicMock() resp.text = 'hi' resp.status_code = 200 return resp with app.test_request_context(): with mock.patch('requests.sessions.Session.send', fake_send): resp = client.get('/api/user') self.assertEqual(resp.text, 'hi') # trigger ctx.authlib_client_oauth_token resp = client.get('/api/user') self.assertEqual(resp.text, 'hi')
def test_init_app_params(self): app = Flask(__name__) oauth = OAuth() oauth.init_app(app, SimpleCache()) self.assertIsNotNone(oauth.cache) self.assertIsNone(oauth.update_token) oauth.init_app(app, update_token=lambda o: o) self.assertIsNotNone(oauth.update_token)
def test_init_app_later(self): app = Flask(__name__) app.config.update({ 'DEV_CLIENT_ID': 'dev', 'DEV_CLIENT_SECRET': 'dev', }) oauth = OAuth() remote = oauth.register('dev') self.assertRaises(RuntimeError, lambda: oauth.dev.client_id) oauth.init_app(app) self.assertEqual(oauth.dev.client_id, 'dev') self.assertEqual(remote.client_id, 'dev') self.assertIsNone(oauth.cache) self.assertIsNone(oauth.fetch_token) self.assertIsNone(oauth.update_token)
def create_app(): app = Flask(__name__) app.config.from_envvar("CONFIG") app.static_folder = "../../canaille/static" oauth = OAuth() oauth.init_app(app) oauth.register( name="yaal", client_id=app.config["OAUTH_CLIENT_ID"], client_secret=app.config["OAUTH_CLIENT_SECRET"], server_metadata_url=get_well_known_url(app.config["OAUTH_AUTH_SERVER"], external=True), client_kwargs={"scope": "openid profile email groups"}, ) @app.route("/") def index(): return render_template("index.html", user=session.get("user"), name=app.config["NAME"]) @app.route("/login") def login(): return oauth.yaal.authorize_redirect( url_for("authorize", _external=True)) @app.route("/authorize") def authorize(): token = oauth.yaal.authorize_access_token() userinfo = oauth.yaal.parse_id_token(token) session["user"] = userinfo flash("You have been successfully logged in.", "success") return redirect(url_for("index")) @app.route("/logout") def logout(): try: del session["user"] except KeyError: pass flash("You have been successfully logged out.", "success") return redirect(url_for("index")) return app
class FlaskOAuth2Client: def init_app( self, app, hydra_url: str, client_id: str, client_secret: str, scope: list[str], cache: Redis, ): self.hydra_url = hydra_url self.client_id = client_id self.oauth = OAuth(cache=cache, fetch_token=self._fetch_token, update_token=self._update_token) self.oauth.register( name='hydra', access_token_url=f'{hydra_url}/oauth2/token', authorize_url=f'{hydra_url}/oauth2/auth', userinfo_endpoint=f'{hydra_url}/userinfo', client_id=client_id, client_secret=client_secret, client_kwargs={'scope': ' '.join(scope)}, ) self.oauth.init_app(app) def login_redirect(self, redirect_uri, **kwargs): """Return a redirect to the Hydra authorization endpoint.""" return self.oauth.hydra.authorize_redirect(redirect_uri, **kwargs) def login_callback(self): """Save the token and log the user in.""" token = self.oauth.hydra.authorize_access_token() userinfo = self.oauth.hydra.userinfo() user_id = userinfo['sub'] if not (token_model := Session.get(OAuth2Token, (self.client_id, user_id))): token_model = OAuth2Token(client_id=self.client_id, user_id=user_id) token_model.token_type = token.get('token_type') token_model.access_token = token.get('access_token') token_model.refresh_token = token.get('refresh_token') token_model.id_token = token.get('id_token') token_model.expires_at = token.get('expires_at') token_model.save() user = Session.get(User, user_id) login_user(user)
def test_request_with_refresh_token(self): app = Flask(__name__) app.secret_key = '!' oauth = OAuth() expired_token = { 'token_type': 'Bearer', 'access_token': 'expired-a', 'refresh_token': 'expired-b', 'expires_in': '3600', 'expires_at': 1566465749, } oauth.init_app(app, fetch_token=lambda name: expired_token) client = oauth.register( 'dev', client_id='dev', client_secret='dev', api_base_url='https://i.b/api', access_token_url='https://i.b/token', refresh_token_url='https://i.b/token', authorize_url='https://i.b/authorize' ) def fake_send(sess, req, **kwargs): if req.url == 'https://i.b/token': auth = req.headers['Authorization'] self.assertIn('Basic', auth) resp = mock.MagicMock() resp.json = get_bearer_token resp.status_code = 200 return resp resp = mock.MagicMock() resp.text = 'hi' resp.status_code = 200 return resp with app.test_request_context(): with mock.patch('requests.sessions.Session.send', fake_send): resp = client.get('/api/user', token=expired_token) self.assertEqual(resp.text, 'hi')
jwt_refresh_token_required, ) from flask_cors import CORS, cross_origin import re import os import smtplib import imghdr from email.message import EmailMessage from itsdangerous import URLSafeTimedSerializer, BadTimeSignature, SignatureExpired from authlib.integrations.flask_client import OAuth import json oauth = OAuth() app = Flask(__name__) oauth.init_app(app) app.secret_key = "markus" setup_db(app, database_path="postgresql://*****:*****@134.122.78.140:5432/register") jwt = JWTManager(app) db = SQLAlchemy(app) CORS(app, resources={r"/*": {"origins": "*"}}) api = Api( app, version="1.0", title="TodoMVC API", description="A simple TodoMVC API", ) bcrypt = Bcrypt() oauth.register(
class AuthLibAuthProvider(AuthProviderBase): def __init__(self, app=None): super(AuthLibAuthProvider, self).__init__(app) if self._app: self._oauth = OAuth(self._app) else: self._oauth = OAuth() self._name = None self._provider = None self._type = "authlib" self._display_name = "Authlib Login" def init_app(self, app): """ Init oauth instance within Flask """ self._app = app self._oauth.init_app(app) def register(self, **kwargs): """ Register openid connect provider """ self._name = kwargs.get("name") self._oauth.register(**kwargs) def login(self, request): """ Start openid connect login procedure """ if self._redirect_uri: redirect_uri = self._redirect_uri else: redirect_uri = url_for("api.aaa_auth", _external=True) self._redirect_uri = redirect_uri self._log.debug( f"Start openid connect login procedure via oidc provider {self._name}" ) self._provider = getattr(self._oauth, self._name) return self._provider.authorize_redirect(redirect_uri) def authorize(self, request): if self._provider: self._access_token = self._provider.authorize_access_token() self._id_token = self._provider.parse_id_token(self._access_token) self._log.debug(self._id_token) self._username = self._id_token.get("preferred_username", self._id_token.get("name")) if not self._username: abort(500, "Did not get a username from token") user = User.query.filter_by(username=self._username).first() if user is None: self._log.info( f"username {self._username} not found in local database -> creating" ) user = User(username=self._username) user.name = self._id_token["name"] else: self._log.info( f"username {self._username} found in local database") user.aaa_provider = self._name user.password_hash = user.hash_password("".join( random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(128) )) # generate max len random secure password on each login db.session.add(user) db.session.commit() user = User.query.filter_by(username=self._username).first() upstream_token = Oauth2UpstreamToken(user_id=user.id, aaa_provider=self._name, **self._access_token) db.session.merge(upstream_token) db.session.commit() self._user = user return True else: self._log.warn( f"AAA provider {self._name} has not been initialized properly") return False def get_token(self): now = timegm(datetime.utcnow().utctimetuple()) db_token = JinjamatorToken.query.filter_by( user_id=self._user.id).first() if db_token: if self._user.verify_auth_token(db_token.access_token): return db_token.access_token upstream_token = Oauth2UpstreamToken.query.filter_by( user_id=self._user.id).first() if upstream_token.expires_at < now: log.debug( f"upstream token {upstream_token.expires_at} for user {self._user.id} expired {now}, refusing to generate a new local one" ) return False else: log.debug( f"upstream token ({upstream_token.expires_at}) for user {self._user.id} valid ({now}) ttl {upstream_token.expires_at - now}" ) log.debug(f"generating new token for user_id: {self._user.id}") return self._user.generate_auth_token().access_token
class OAuthModule(bp.AuthModule): def __init__(self, app, bp): super(OAuthModule, self).__init__(app, bp) self.oauth = OAuth() self.oauth.init_app(app) self.app = self.register_oauth(self.oauth, app) bp.route("/login", methods=["POST"])(self.login) bp.route("/authorize", methods=["GET"])(self.authorize) @abc.abstractmethod def register_oauth(self, oauth, app): pass @abc.abstractmethod def get_login_form_button_text(self): pass @overrides def is_flat(self) -> bool: return True @overrides def can_manage_users(self) -> bool: return False @overrides def get_login_form(self) -> models.LoginForm: return models.LoginForm([], self.get_login_form_button_text()) def login(self) -> Response: if "return_to" in request.args: redirect = self.app.authorize_redirect( request.args.get("return_to"), response_type="token") else: redirect = self.app.authorize_redirect(response_type="token") return jsonify(redirect.headers["Location"]) def authorize(self): authorization_response = request.full_path + "#" + request.args.get( "fragment") try: token = self.app.fetch_access_token( authorization_response=authorization_response) except Exception as e: traceback.print_exc() raise exceptions.SecurityError(description=str(e)) access_token = token["access_token"] secret = current_app.config["VEGAS_CLIENT_SECRET"] try: decoded = jwt.decode(access_token, secret, verify=False) decoded = jwt.decode(access_token, secret, verify=True, audience=decoded["aud"]) except jwt.exceptions.InvalidTokenError as e: traceback.print_exc() raise exceptions.SecurityError(description=str(e)) session["auth"] = { "user": OAuthUser(decoded).to_dict(), "user_data": decoded, "token": token } log.access_flask_login() return jsonify(self.get_logged_in_user())
class OAuthModule(bp.AuthModule): def __init__(self, app, bp, secret, algorithms: typing.List[str] = ["HS256"]): super(OAuthModule, self).__init__(app, bp) self.oauth = OAuth() self.oauth.init_app(app) self.app = self.register_oauth(self.oauth, app) self.secret = secret self.algorithms = algorithms bp.route("/login", methods=["POST"])(self.login) bp.route("/authorize", methods=["GET"])(self.authorize_get) bp.route("/authorize", methods=["POST"])(self.authorize_post) auth.verify_token_callback = lambda t: self.verify_token(t) @abc.abstractmethod def register_oauth(self, oauth, app): pass @abc.abstractmethod def get_login_form_button_text(self): pass @overrides def is_flat(self) -> bool: return True @overrides def can_manage_users(self) -> bool: return False @overrides def get_login_form(self) -> models.LoginForm: return models.LoginForm([], self.get_login_form_button_text()) @auth.login_required(optional=True) @overrides def get_logged_in_user(self): # if user set in cookie, use that user = super(OAuthModule, self).get_logged_in_user() if user != None: return user # otherwise check bearer auth ret = auth.current_user() if ret != None: (token, user) = ret if user != None: LOGGER.info( "User has logged in via bearer auth; setting session.") self._update_session(user, token) return super(OAuthModule, self).get_logged_in_user() def login(self) -> Response: if "return_to" in request.args: redirect = self.app.authorize_redirect( request.args.get("return_to"), response_type="token") else: redirect = self.app.authorize_redirect(response_type="token") return jsonify(redirect.headers["Location"]) def make_user(self, decoded: dict) -> OAuthUser: return OAuthUser(decoded, id_field="sub") def verify_token(self, access_token: str) -> OAuthUser: if not access_token: return None LOGGER.info("Verifying token: \"%s\"", access_token) try: decoded = jwt.decode(access_token, options={"verify_signature": False}) decoded = jwt.decode(access_token, self.secret, audience=decoded["aud"], algorithms=self.algorithms) except jwt.exceptions.InvalidTokenError as e: traceback.print_exc() sys.stderr.flush() raise exceptions.SecurityError(description=str(e)) LOGGER.info("Decoded and validated token: {}".format(decoded)) return ({"access_token": access_token}, self.make_user(decoded)) def _update_session(self, user: OAuthUser, token: dict): session["auth"] = { "user": user.to_dict(), "user_data": user.data, "token": token } log.access_flask_login() def _authorize(self, authorization_response): try: token = self.app.fetch_access_token( authorization_response=authorization_response) except Exception as e: traceback.print_exc() sys.stderr.flush() raise exceptions.SecurityError(description=str(e)) (_, user) = self.verify_token(token["access_token"]) self._update_session(user, token) return jsonify(self.get_logged_in_user()) def authorize_post(self): body = request.get_json() if not body: raise exceptions.BadRequest() LOGGER.info("Received authorize POST with body {}".format(body)) authorization_response = request.full_path + "#" + urllib.parse.urlencode( body) return self._authorize(authorization_response) def authorize_get(self): LOGGER.info("Received authorize GET with fragment {}".format( request.args.get("fragment"))) authorization_response = request.full_path + "#" + request.args.get( "fragment") return self._authorize(authorization_response)
def create_app(): # Configuración inicial de la app app = Flask(__name__) cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) app.config.from_object(Config) fa = FontAwesome(app) app.config['SESSION_TYPE'] = 'filesystem' app.config['UPLOAD_FOLDER'] = 'app/static/uploads' Session(app) # OAuth2 oauth = OAuth() oauth.init_app(app) google = oauth.register( name = 'google', client_id = '593639469284-m7lqdnnjqrsou05rjv5mm7cda944cdg2.apps.googleusercontent.com', client_secret = 'tX5Zvj88bp1La0OuE1ubYvLN', access_token_url = 'https://accounts.google.com/o/oauth2/token', access_token_params = None, authorize_url= 'https://accounts.google.com/o/oauth2/auth', authorize_params= None, api_base_url='https://www.googleapis.com/oauth2/v1/', client_kwargs={'scope': 'openid profile email'}, ) @app.route('/login_with_google') def login_with_google(): google = oauth.create_client('google') redirect_uri = url_for('authorize', _external=True) return google.authorize_redirect(redirect_uri) @app.route('/authorize') def authorize(): google = oauth.create_client('google') token = google.authorize_access_token() resp = google.get('userinfo') resp.raise_for_status() profile = resp.json() # do something with the token and profile if User.get_by_email(profile['email']): session['usuario'] = User.get_by_email(profile['email']) return redirect('/') # Configuracion de la BD app.secret_key = 'hola' app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://" + \ Config.DB_USER+":"+Config.DB_PASS+"@"+Config.DB_HOST+"/"+Config.DB_NAME db.init_app(app) app.config['SESSION_TYPE'] = 'filesystem' Session(app) # Autenticacion app.add_url_rule('/login', 'login', user.login, methods=["GET", "POST"]) app.add_url_rule('/logout', 'logout', user.logout) # Endpoints para api de centros app.add_url_rule('/api/centros', 'api_centros', centros.mostrar_centros, methods=["GET"]) app.add_url_rule('/api/centros/page/<int:page>', 'api_centros', centros.mostrar_centros, methods=["GET"]) app.add_url_rule('/api/centros/<int:id>', 'api_centro', centros.mostrar_centro, methods=["GET"]) app.add_url_rule('/api/centros/todos', 'mostrar_todos_centros', centros.mostrar_todos_centros, methods=["GET"]) app.add_url_rule('/api/crear_centro', 'api_crear_centro', centros.cargarCentros, methods=["GET", "POST"]) # Endpoints para api de turnos app.add_url_rule('/api/centros/id_centro/<int:id_centro>/turnos_disponibles/fecha=<fecha>', 'turnos_disponibles', turnos.turnos_disponibles, methods=["POST", "GET"]) app.add_url_rule('/api/centros/id_centro/<int:id_centro>/reserva', 'pedir_reserva', turnos.pedir_reserva, methods=["POST", "GET"]) # Endpoints para api de estadisticas app.add_url_rule('/api/estadisticas/tipos', 'centros_por_tipos', centros.centros_por_tipos, methods=["GET"]) app.add_url_rule('/api/estadisticas/top10_centros_del_mes', 'top10_centros_del_mes', centros.top10_centros_del_mes, methods=["GET"]) app.add_url_rule('/api/estadisticas/total_turnos_del_mes', 'total_turnos_del_mes', centros.total_turnos_del_mes, methods=["GET"]) # Endpoints para Configuracion del Sitio app.add_url_rule('/configuracion/vista_configuracion', 'vista_configuracion', config.vista_configuracion, methods=["POST", "GET"]) # Endpoints para centros app.add_url_rule('/centros', 'centros', centros_de_ayuda.go_index, methods=["POST", "GET"]) app.add_url_rule('/centros/page/<int:page>', 'centros', centros_de_ayuda.go_index, methods=["POST", "GET"]) app.add_url_rule('/centros/nombre/<nombre>/estado/<estado>/page/<int:page>', 'centros', centros_de_ayuda.go_index, methods=["POST", "GET"]) app.add_url_rule('/centros/crear_centro', 'crear_centro', centros_de_ayuda.crear_centro, methods=["POST", "GET"]) app.add_url_rule('/centros/editar_centro/<id>', 'editar_centro', centros_de_ayuda.editar_centro, methods=['POST', 'GET']) app.add_url_rule('/centros/borrar_centro/<id>', 'borrar_centro', centros_de_ayuda.borrar_centro, methods=['POST', 'GET']) app.add_url_rule('/centros/aprobar_centro/<id>', 'aprobar_centro', centros_de_ayuda.aprobar_centro, methods=["POST", "GET"]) app.add_url_rule('/centros/rechazar_centro/<id>', 'rechazar_centro', centros_de_ayuda.rechazar_centro, methods=["POST", "GET"]) app.add_url_rule('/centros/publicar_centro/<id>', 'publicar_centro', centros_de_ayuda.publicar_centro, methods=["POST", "GET"]) app.add_url_rule('/centros/despublicar_centro/<id>', 'despublicar_centro', centros_de_ayuda.despublicar_centro, methods=["POST", "GET"]) app.add_url_rule('/centros/mostrar_centro/<id>', 'mostrar_centro', centros_de_ayuda.mostrar_centro, methods=["POST", "GET"]) # Endpoints para Usuarios app.add_url_rule('/usuario/edit_usuario/<id>', 'edit_usuario', user.edit_usuario, methods=['POST', 'GET']) app.add_url_rule('/usuario/index_usuario', 'index_usuario', user.index_usuario, methods=["POST", "GET"]) app.add_url_rule('/usuario/crear_usuario', 'crear_usuario', user.crear_usuario, methods=["POST", "GET"]) app.add_url_rule("/usuarios/borrar_usuario/<id>", 'borrar_usuario', user.borrar, methods=['GET']) app.add_url_rule("/usuarios/borrar_usuario_por_nombre/<nombre>", 'borrar_usuario_por_nombre', user.borrar_por_nombre, methods=['GET']) app.add_url_rule('/usuarios/activar/<id>', 'activar', user.activar, methods=['POST', 'GET']) app.add_url_rule('/usuarios/desactivar/<id>', 'desactivar', user.desactivar, methods=['POST', 'GET']) app.add_url_rule('/usuarios/page/<int:page>', 'index_usuario', user.index_usuario, methods=["POST", "GET"]) app.add_url_rule('/usuarios/nombre/<nombre>/estado/<estado>/page/<int:page>', 'index_usuario', user.index_usuario, methods=["POST", "GET"]) # Endpoints para Turnos app.add_url_rule('/turnos_para_centro/index_turno', 'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/page/<int:page>', 'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/index_turno', 'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/index_turno/id/<id>', 'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/page/<int:page>/id/<id>', 'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/email/<email>/page/<int:page>', 'index_turno', turnos_para_centro.index_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/crear_turno', 'crear_turno', turnos_para_centro.crear_turno, methods=["POST", "GET"]) # Modificacion de turnos 04 February 2021 (Thursday) app.add_url_rule('/turnos_para_centro/crear_turno/<int:id_centro>', 'crear_turno', turnos_para_centro.crear_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/crear_turno/<int:id_centro>/fecha=<fecha>', 'crear_turno_para_fechax', turnos_para_centro.crear_turno_para_fecha, methods=["POST", "GET"]) # Modificacion de turnos 06 February 2021 (Saturday) app.add_url_rule('/turnos_para_centro/crear_turno', 'crear_turno_para_fecha', turnos_para_centro.crear_turno_para_fecha, methods=["POST"]) # /04 February 2021 (Thursday) app.add_url_rule('/turnos_para_centro/editar_turno/<id>', 'editar_turno', turnos_para_centro.editar_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/borrar_turno/<id>', 'borrar_turno', turnos_para_centro.borrar_turno, methods=["POST", "GET"]) app.add_url_rule('/turnos_para_centro/sacar_turno/<id>', 'sacar_turno', turnos_para_centro.sacar_turno, methods=["POST", "GET"]) # Manejo de errores @app.errorhandler(404) def page_not_found(e): return render_template('errores/404.html'), 404 @app.errorhandler(503) def page_not_found(e): return render_template('errores/503.html'), 503 @app.errorhandler(401) def page_not_found(e): return render_template('errores/401.html'), 401 @app.errorhandler(403) def page_not_found(e): return render_template('errores/403.html'), 403 @app.route('/') def index(): if permisos.sitio_cerrado() and permisos.no_es_admin(): abort(503) configuracion = Configuracion.get_config() return render_template('index.html', configuracion=configuracion) return app