def add_auth_controllers(app: Flask, config: Config, db: Database): oauth = OAuth(app, Cache()) def handle_authorize(remote, token, user_info): sub = user_info['sub'] email = user_info['email'] user_info['providerName'] = remote.name session['user_info'] = user_info with db.session_scope() as conn: user = conn.query(User).filter( or_(User.sub == sub, and_(User.email == email, User.email != None))).first() if not user: user = User(sub=sub, email=email) conn.add(user) user.email = email user.name = user_info['name'] user.avatar = user_info['picture'] conn.flush() session['user_id'] = user.id return redirect('/') for backend in backends: bp = create_flask_blueprint(backend, oauth, handle_authorize) app.register_blueprint(bp, url_prefix='/{}'.format(backend.OAUTH_NAME)) @app.route('/logout') def logout(): # pylint: disable=unused-variable del session['user_info'] del session['user_id'] return redirect('/')
def init_app(self, app): self.app = app app.auth_manager = self app.context_processor(_user_context_processor) app.context_processor(_user_roles_context_processor) if app.config.get('AUTH_METHOD') == 'google': app.config.setdefault('GOOGLE_ALLOWED_DOMAINS', []) from authlib.flask.client import OAuth self.oauth = OAuth(app) from loginpass import create_flask_blueprint from loginpass.google import Google from .google import handle_authorize google_bp = create_flask_blueprint(Google, self.oauth, handle_authorize) app.register_blueprint(google_bp, url_prefix='/auth/google') self.login_view = 'loginpass_google.login' elif app.config.get('AUTH_METHOD') == 'oidc': from authlib.flask.client import OAuth self.oauth = OAuth(app) from loginpass import create_flask_blueprint from .oidc import create_oidc_backend, handle_authorize backend = create_oidc_backend('oidc', app.config['OIDC_CLIENT_SECRETS'], app.config.get('OIDC_SCOPES')) oidc_bp = create_flask_blueprint(backend, self.oauth, handle_authorize) app.register_blueprint(oidc_bp, url_prefix='/auth/oidc') self.login_view = 'loginpass_oidc.login' else: from . import local_views app.register_blueprint(local_views.bp, url_prefix='/auth/local') self.login_view = 'auth_local.login' from . import views app.register_blueprint(views.bp, url_prefix='/auth')
def init_oauth(app): oauth2_client.init_app(app, fetch_token=fetch_token, update_token=update_token) backends = [loginpass.Google, loginpass.Facebook] loginpass_bp = loginpass.create_flask_blueprint( backends, oauth2_client, handle_authorize_oauth2) app.register_blueprint(loginpass_bp)
def init_oauth(app): oauth2_client.init_app(app, fetch_token=fetch_token, update_token=update_token) oauth2_client.register("engpsu") backends = [loginpass.Google] loginpass_bp = loginpass.create_flask_blueprint(backends, oauth2_client, handle_authorize_google) app.register_blueprint(loginpass_bp)
def init_oauth(app): oauth2_client.init_app(app, fetch_token=fetch_token, update_token=update_token) oauth2_client.register('engpsu') # oauth2_client.register('google') google_bp = loginpass.create_flask_blueprint(loginpass.Google, oauth2_client, handle_authorize_google) app.register_blueprint(google_bp, url_prefix='/google')
def setup_authentication(app): oauth = OAuth(app) def handle_redirects(remote, token, user_info): if not 'hd' in user_info or user_info['hd'] != app.config['OAUTH_DOMAIN']: return redirect(url_for('page.login')) session['user'] = user_info return redirect(session.get('next', '/')) def ensure_user_is_authorized(app): if 'user' not in session and request.path not in ['/oauth/login', '/oauth/auth', '/login', '/healthcheck'] and not request.path.startswith('/static/'): session['next'] = request.url return redirect(url_for('page.login')) app.register_blueprint( create_flask_blueprint(Google, oauth, handle_redirects), url_prefix='/oauth') app.before_request(lambda: ensure_user_is_authorized(app))
def configure(app): """Configure OAuth and register auth blueprint.""" def handle_authorize(remote, token, user_info): return _handle_authorize(app.bert_e, user_info) # configure web oauth if app.bert_e.settings.repository_host == 'github': backend = GitHub app.config['GITHUB_CLIENT_ID'] = app.config['CLIENT_ID'] app.config['GITHUB_CLIENT_SECRET'] = app.config['CLIENT_SECRET'] else: backend = Bitbucket app.config['BITBUCKET_CLIENT_ID'] = app.config['CLIENT_ID'] app.config['BITBUCKET_CLIENT_SECRET'] = app.config['CLIENT_SECRET'] oauth = OAuth(app) bp = create_flask_blueprint(backend, oauth, handle_authorize) app.register_blueprint(bp) # create additional path for token based authentication bp = Blueprint('auth', __name__) remote = register_to(backend, oauth, RemoteApp) @bp.route('/api/auth') def api_auth(): access_token = request.args.get('access_token') if access_token: token = {'access_token': access_token, 'token_type': 'bearer'} user_info = remote.profile(token=token) return handle_authorize(remote, access_token, user_info) return unauthorized('Missing access token in request.') @bp.route('/logout') def logout(): session.pop('user') session.pop('admin') return redirect(url_for('status page.display')) app.register_blueprint(bp)
def initialize_app(flask_app): # Register blueprints blueprint = Blueprint('api', __name__, url_prefix='/api') api.init_app(blueprint) # Add namespaces api.add_namespace(auth_ns) api.add_namespace(users_ns) api.add_namespace(resources_ns) flask_app.register_blueprint(blueprint) # Create blueprint for GitHub github_blueprint = create_flask_blueprint(GitHub, oauth, handle_oauth2_authorization) app.register_blueprint(github_blueprint, url_prefix='/github') # Configure OAuth2.0 oauth.init_app(app) # Initialize database init_db()
return (render_template('result.html'), 404) @app.errorhandler(403) def permission_denied(e): return redirect(url_for('login')) @app.route('/webhook', methods=['POST']) def webhook(): app.logger.debug('Headers: %s', request.headers) app.logger.debug('Body: %s', request.get_data()) return 'OK' twitter_bp = create_flask_blueprint(Twitter, oauth, handle_authorize) app.register_blueprint(twitter_bp, url_prefix='/twitter') app.logger.setLevel(logging.DEBUG) start_demo_db = False if 'development' == app.config.get('ENV'): if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': # This is the process that will be killed and restarted. # Can't do anything here, so just wait for the end. time.sleep(3600) start_demo_db = True app.logger.info("App %s started. Env is %s" % (__name__, app.config.get('ENV'))) app.logger.debug("Logging at DEBUG level.") game = Game(applog=app.logger, start_demo_db=start_demo_db) app.logger.debug("Game connected.")
def create_app(settings_override=None, register_security_blueprint=True): """Returns the frontend application instance""" app = factory.create_app(__name__, __path__, settings_override) app.wsgi_app = WhiteNoise(app.wsgi_app, root=app.static_folder, prefix='static/') # Init assets assets.init_app(app) webpack.init_app(app) oauth.init_app(app) menu.init_app(app) gravatar.init_app(app) userdatastore = SQLAlchemyUserDatastore(db, models.User, models.Role) security_ctx = security.init_app( app, userdatastore, login_form=DeploymentLoginForm, register_blueprint=register_security_blueprint) @security_ctx.send_mail_task def delay_flask_security_mail(msg): send_email.delay(subject=msg.subject, sender=msg.sender, recipients=msg.recipients, body=msg.body) # initialize the OpenAPI extension spec = APISpec(title='Apollo', version='1.0.0', openapi_version='3.0.2', plugins=[MarshmallowPlugin()]) app.config.update({'APISPEC_SPEC': spec}) docs.init_app(app) csrf.init_app(app) init_admin(admin, app) monitor(app) # Register custom error handlers if not app.debug: for e in [500, 404, 403]: app.register_error_handler(e, handle_error) # register deployment selection middleware app.before_request(set_request_presets) # add Jinja2 filters app.jinja_env.filters.update(custom_filters) # Login and logout signal handlers user_logged_out.connect(clear_session) @identity_loaded.connect_via(app) def on_identity_loaded(sender, identity): if current_user.is_authenticated: user = current_user._get_current_object() needs = services.users.get_permissions_cache(user) for need in needs: identity.provides.add(need) @app.context_processor def inject_permissions(): ga_key = app.config.get('GOOGLE_ANALYTICS_KEY') gtm_key = app.config.get('GOOGLE_TAG_MANAGER_KEY') return dict(perms=permissions, ga_key=ga_key, gtm_key=gtm_key) # clickjacking protection @app.after_request def frame_buster(response): response.headers['X-Frame-Options'] = app.config.get( 'X_FRAME_OPTIONS', 'DENY') return response # content security policy @app.after_request def content_security_policy(response): response.headers['Content-Security-Policy'] = "default-src 'self' " + \ "*.googlecode.com *.google-analytics.com fonts.gstatic.com fonts.googleapis.com " + \ "*.googletagmanager.com " + \ "cdn.heapanalytics.com heapanalytics.com " + \ "'unsafe-inline' 'unsafe-eval' data:; img-src * data:" return response def handle_authorize(remote, token, user_info): if user_info and 'email' in user_info: user = models.User.query.filter_by( email=user_info['email']).first() if user: login_user(user) userdatastore.commit() return redirect(app.config.get('SECURITY_POST_LOGIN_VIEW')) return redirect(url_for_security('login')) @app.template_global() def modify_query(**values): args = request.args.copy() for k, v in values.items(): if not v: _ = args.pop(k, None) else: args[k] = v return '{}?{}'.format(request.path, url_encode(args)) facebook_bp = create_flask_blueprint(Facebook, oauth, handle_authorize) google_bp = create_flask_blueprint(Google, oauth, handle_authorize) if app.config.get('ENABLE_SOCIAL_LOGIN', False): app.register_blueprint(facebook_bp, url_prefix='/facebook') app.register_blueprint(google_bp, url_prefix='/google') return app
def register(app): """generates several flask blueprint for authentication (google,b2access) using authlib and loginpass registers these blueprints into Flask app instance and adds implementation of logout method + appropriate endpoint """ oauth = OAuth(app) # registering flask blueprint with /b2access/login and /b2access/auth endpoints supporting oauth workflow b2accessbp = create_flask_blueprint(B2Access, oauth, handle_authorize_b2access) app.register_blueprint(b2accessbp, url_prefix='/b2access') # registering flask blueprint with /google/login and /google/auth endpoints supporting oauth workflow googlebp = create_flask_blueprint(Google, oauth, handle_authorize_google) app.register_blueprint(googlebp, url_prefix='/google') # registering flask endpoint to logout from any of the idp @app.route('/b2access/logout') @app.route('/google/logout') def logout(): session.pop(AUTH_TOKEN_KEY, None) session.pop(AUTH_REFRESH_TOKEN, None) session.pop(USER_INFO, None) return redirect(BASE_URI, code=302) # register flask endpoint for getting user information @app.route('/userinfo') def index(): if is_logged_in(): user_info = get_user_info() return jsonify(user_info) #(token == 'test' and request.host == 'localhost:5000') # return test user info in case of local deployment if (request.headers.get('authorization') == 'Basic dGVzdDp0ZXN0' and request.host == 'localhost:5000'): users = app.data.driver.db['userprofile'] a = users.find_one({'id': '0001'}) ui = {"name": "Test", "id": "0001"} if a != None: #a['token'] = ui['token'] ui = a ui['_id'] = str(ui['_id']) return jsonify(ui) return jsonify({"name": "Guest", "status": "not logged in."}) def get_user_info(): """"function to return user information stored in current session""" ui = session[USER_INFO] ui['token'] = session[AUTH_TOKEN_KEY] #if (ui['token'] == 'test' and request.host == 'localhost:5000'): # ui['id']='0001' #check whether user exists in DB, and update fields accordingly users = app.data.driver.db['userprofile'] a = users.find_one({'id': ui['id']}) if a != None: #print(a) a['token'] = ui['token'] ui = a ui['_id'] = str(ui['_id']) #print('get_user_info',ui['name']) return ui @app.route('/interface_main', methods=['POST']) def compatibility_redirect(): #""" redirects old POST request with target id and source to GET request to new UI with params in url""" targetsource = request.form.get('subject_tofeed', '') # source - direct link to file # request.form['recordurl_tofeed'] this is ignored in b2note v 1.0 targetid = request.form.get('pid_tofeed', '') # id - landingpage redirecturl = ('' if not BASE_URI else BASE_URI) + '/#/b2note_home/id=' + str( targetid) + '&source=' + str(targetsource) # /#/b2note_home/id=https:/someurl/sdf&source=http://someurl return redirect(redirecturl, code=303)
def create_app(app_name=PKG_NAME, **kwargs): """Start app. Setup config profiles as needed.""" app = Flask(__name__) # instance_relative_config=True, static_folder='./frontend/build', static_url_path='/') if app.config['ENV'] == "production": app.config.from_object("config.ProductionConfig") elif app.config['ENV'] == "testing": app.config.from_object("config.TestingConfig") else: app.config.from_object("config.DevelopmentConfig") # if kwargs.get('celery'): # init_celery(kwargs.get('celery'), app) login.init_app(app) db.init_app(app) ma.init_app(app) cors.init_app(app, resources={r"/api/v1/*": { "origins": "http://*****:*****@legacydirectional.com', # toaddrs=['*****@*****.**'], subject='Website Error', # credentials=auth, secure=secure) # # mail_handler.setLevel(logging.WARNING) # mail_handler.setFormatter(email_request_formatter) # app.logger.addHandler(mail_handler) # if not os.path.exists('logs'): # os.mkdir('logs') # app.logger.setLevel(logging.INFO) # app.logger.info('Legacy startup') return app
if not token or not user_info: raise RequestError(code=400, message="Missing OAuth token or user info") # Find existing user, add to logged in user, or create a new user user = Connection.get_user_by_connection( site=remote.name, site_id=user_info['preferred_username']) if not user: user = get_authed_user() if not user: user = User() connection = Connection( userid=user.id, site=remote.name, site_id=user_info['preferred_username'], site_username=user_info['preferred_username'], ) user.connections.append(connection) db.session.add(user) db.session.add(connection) db.session.commit() # Set them as logged in in the session session['user_id'] = user.id redirect_url = frontend_url('/user/me') return redirect(redirect_url) github_blueprint = create_flask_blueprint(GitHub, oauth, handle_authorize) gitlab_blueprint = create_flask_blueprint(Gitlab, oauth, handle_authorize)
print("Found and using privileged token (eg, for account signup)") priv_api = auth_api(Config.FATCAT_API_AUTH_TOKEN) else: print("No privileged token found") priv_api = None # TODO: refactor integration so this doesn't always need to be definied. If # key/secret are empty, library will not init; if init is skipped, get # undefined errors elsewhere. mwoauth = MWOAuth( consumer_key=Config.WIKIPEDIA_CLIENT_ID or "dummy", consumer_secret=Config.WIKIPEDIA_CLIENT_SECRET or "dummy", default_return_to='wp_oauth_finish_login') mwoauth.handshaker.user_agent = "fatcat.wiki;python_web_interface" app.register_blueprint(mwoauth.bp, url_prefix='/auth/wikipedia') from fatcat_web import routes, editing_routes, auth, cors, forms # TODO: blocking on ORCID support in loginpass if Config.ORCID_CLIENT_ID: orcid_bp = create_flask_blueprint(ORCiD, oauth, auth.handle_oauth) app.register_blueprint(orcid_bp, url_prefix='/auth/orcid') if Config.GITLAB_CLIENT_ID: gitlab_bp = create_flask_blueprint(Gitlab, oauth, auth.handle_oauth) app.register_blueprint(gitlab_bp, url_prefix='/auth/gitlab') if Config.GITHUB_CLIENT_ID: github_bp = create_flask_blueprint(GitHub, oauth, auth.handle_oauth) app.register_blueprint(github_bp, url_prefix='/auth/github')
def load(app): url_prefix = "/oidc" oidc_login_backend = app.config.setdefault('OIDC_LOGIN_BACKEND', os.environ.get('OIDC_LOGIN_BACKEND', None)) create_missing_user = app.config.setdefault('OIDC_CREATE_MISSING_USER', os.environ.get('OIDC_CREATE_MISSING_USER', False)) def get_user(email): user = Users.query.filter_by(email=email).first() if user is not None: log('logins', "[{date}] {ip} - " + email + " - OIDC bridged user found") return user def create_user(email, name): log('logins', "[{date}] {ip} - " + email + " - No OIDC bridged user found, creating user") user = Users(email=email, name=name.strip(), verified=True) db.session.add(user) db.session.commit() return user def get_or_create_user(email, name): user = get_user(email) if user is not None: return user if create_missing_user: return create_user(email, name) else: log('logins', "[{date}] {ip} - " + email + " - No OIDC bridged user found and not configured to create missing users") return None def handle_authorize(remote, token, user_info): with app.app_context(): user = get_or_create_user( email=user_info["email"], name=user_info["name"]) if user is not None: session.regenerate() login_user(user) log("logins", "[{date}] {ip} - " + user.name + " logged in") db.session.close() return redirect(url_for("challenges.listing")) return redirect('/') def create_azure_backend(name, tenant='common'): metadata_url = f'https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration' class AzureAD(object): NAME = name OAUTH_CONFIG = { 'api_base_url': 'https://graph.microsoft.com/', 'server_metadata_url': metadata_url, 'client_kwargs': {'scope': 'openid email profile'}, } def load_server_metadata(self): metadata = super(AzureAD, self).load_server_metadata() # fix issuer value issuer = metadata['issuer'] issuer = issuer.replace('{tenantid}', tenant) metadata['issuer'] = issuer return metadata return AzureAD backend = None if oidc_login_backend == 'azure': app.config.setdefault('AZURE_TENANT_ID', os.environ.get('AZURE_TENANT_ID', 'common')) app.config.setdefault('AZURE_CLIENT_ID', os.environ.get('AZURE_CLIENT_ID', 'missing_client_id')) app.config.setdefault('AZURE_CLIENT_SECRET', os.environ.get('AZURE_CLIENT_SECRET', 'missing_client_secret')) backend = create_azure_backend('azure', app.config['AZURE_TENANT_ID']) else: print('** Skip loading CTFd-OIDC because of the unknown or unsupported OIDC backend **') return oauth = OAuth(app) bp = create_flask_blueprint([backend], oauth, handle_authorize) app.register_blueprint(bp, url_prefix=url_prefix) ############################### # Application Reconfiguration # ############################### # ('', 204) is "No Content" code set_config('registration_visibility', False) app.view_functions['auth.login'] = lambda: redirect( url_prefix + "/login/" + oidc_login_backend) app.view_functions['auth.register'] = lambda: ('', 204) app.view_functions['auth.reset_password'] = lambda: ('', 204) app.view_functions['auth.confirm'] = lambda: ('', 204)
def init(app, db, config, base_prefix='/auth', root_uri='/', providers=['google', 'facebook', 'github'], smtp=None, fix_ssl=True): """ Initalize framework Args: app: Flask app db: pyaltt2.db.Database object config: configuration dict base_prefix: base prefix for auth urls root_uri: default next uri providers: oauth2 providers list smtp: pyaltt2.mail.SMTP object, required if email confirmations are used fix_ssl: force SSL everywhere (True by default) """ if not app.config.get('SECRET_KEY'): app.config['SECRET_KEY'] = gen_random_str() _d.x_prefix, _d.dot_prefix = _format_prefix(base_prefix) _d.db = db.clone(rq_func=rq) _d.kv = KVStorage(db=db, table_name='webauth_kv') _d.root_uri = root_uri _d.smtp = smtp if fix_ssl: from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1) def init_db(): from sqlalchemy import (MetaData, Table, Column, BigInteger, VARCHAR, JSON, CHAR, DateTime, ForeignKey, Index, Boolean, Numeric) meta = MetaData() user = Table( 'webauth_user', meta, Column('id', BigInteger(), primary_key=True, autoincrement=True), Column('email', VARCHAR(255), nullable=True, unique=True), Column('password', CHAR(64), nullable=True), Column('api_key', CHAR(32), nullable=True, unique=True), Index('webauth_user_api_key', 'api_key'), Column('d_created', DateTime(timezone=True), nullable=False), Column('d_active', DateTime(timezone=True), nullable=True), Column('confirmed', Boolean, nullable=False, server_default='0'), Column('otp', Numeric(1, 0), nullable=False, server_default='0'), Column('otp_secret', CHAR(16), nullable=True)) user_auth = Table( f'webauth_user_auth', meta, Column('id', BigInteger(), primary_key=True, autoincrement=True), Column('user_id', BigInteger(), ForeignKey('webauth_user.id', ondelete='CASCADE'), nullable=False), Index('webauth_user_auth_user_id', 'user_id'), Column('provider', VARCHAR(15), nullable=False), Column('sub', VARCHAR(255), nullable=False), Column('name', VARCHAR(255), nullable=True), Index('webauth_user_auth_sub_provider', 'sub', 'provider', unique=True)) user_log = Table( f'webauth_user_log', meta, Column('id', BigInteger(), primary_key=True, autoincrement=True), Column('user_id', BigInteger(), nullable=False), Index('webauth_user_log_user_id', 'user_id'), Column('d', DateTime(timezone=True), nullable=False), Column('event', VARCHAR(1024), nullable=False), Column('ip', VARCHAR(45), nullable=False)) meta.create_all(db.connect()) def handle_authorize(remote, token, user_info): if user_info: try: provider = remote if isinstance(remote, str) else remote.name user_id = _handle_user_auth(user_info, provider=provider) touch(user_id) session[f'{_d.x_prefix}user_id'] = user_id session[f'{_d.x_prefix}user_picture'] = user_info.picture session[f'{_d.x_prefix}user_name'] = _get_oauth_user_name( user_info, provider) session[f'{_d.x_prefix}user_confirmed'] = True _call_handler('account.login', user_id=user_id) _log_user_event(f'account.login:{provider}') return redirect(_next_uri()) except ResourceAlreadyExists: response = _call_handler('exception.provider_exists') return response if response else Response( 'oauth provider is already ' + 'registered for another account', status=409) except AccessDenied: response = _call_handler('exception.registration_denied') return response if response else Response( 'account registration is disabled', status=403) # session.permanent = True else: response = _call_handler('exception.provider_failed') return response if response else Response('forbidden', status=403) def google_login(): redirect_uri = url_for(f'{_d.dot_prefix}google.auth', _external=True) return oauth.google.authorize_redirect(redirect_uri) def google_auth(): token = oauth.google.authorize_access_token() user_info = oauth.google.parse_id_token(token) return handle_authorize('google', token, user_info) for k in config: app.config[k.upper().replace('-', '_')] = config_value(config=config, config_path=k) oauth = OAuth(app) app.add_url_rule(f'{base_prefix}/logout', f'{_d.dot_prefix}.logout', logout, methods=['GET']) app.add_url_rule(f'{base_prefix}/confirm/<key>', f'{_d.dot_prefix}confirm', handle_confirm, methods=['GET']) for p in providers: if p == 'google': oauth.register( 'google', server_metadata_url= 'https://accounts.google.com/.well-known/openid-configuration', client_kwargs={'scope': 'openid profile'}, ) app.add_url_rule(f'{base_prefix}/google/login', f'{_d.dot_prefix}google.login', google_login, methods=['GET']) app.add_url_rule(f'{base_prefix}/google/auth', f'{_d.dot_prefix}google.auth', google_auth, methods=['GET']) else: blueprint = loginpass.create_flask_blueprint( _provider_mod[p], oauth, handle_authorize) app.register_blueprint(blueprint, url_prefix=f'{base_prefix}/{p}') init_db() return
# Grabs sentry config from SENTRY_DSN environment variable sentry = Sentry(app) conf = fatcat_client.Configuration() conf.host = Config.FATCAT_API_HOST api = fatcat_client.DefaultApi(fatcat_client.ApiClient(conf)) # remove most jinja2 template whitespace app.jinja_env.trim_blocks = True app.jinja_env.lstrip_blocks = True def auth_api(token): conf = fatcat_client.Configuration() conf.api_key["Authorization"] = token conf.api_key_prefix["Authorization"] = "Bearer" conf.host = Config.FATCAT_API_HOST return fatcat_client.DefaultApi(fatcat_client.ApiClient(conf)) if Config.FATCAT_API_AUTH_TOKEN: print("Found and using privileged token (eg, for account signup)") priv_api = auth_api(Config.FATCAT_API_AUTH_TOKEN) else: print("No privileged token found") priv_api = None from fatcat_web import routes, auth, cors gitlab_bp = create_flask_blueprint(Gitlab, oauth, auth.handle_oauth) app.register_blueprint(gitlab_bp, url_prefix='/auth/gitlab')
session[token_session_key] = token return token oauth = OAuth(app, fetch_token=fetch_token, update_token=update_token) # Define gitlab login handler def handle_authorize(remote, token, user_info): session['user'] = user_info session['token'] = token return redirect(url_for('facts')) gitlab_backend = create_gitlab_backend(OAUTH_APP_NAME, GITLAB_HOST) bp = create_flask_blueprint([gitlab_backend], oauth, handle_authorize) app.register_blueprint(bp, url_prefix='') @app.route('/', methods=['GET', 'POST']) def facts(): user = session.get('user', None) if user is None: return render_template('login.html') return redirect('/login/gitlab') user['id'] = int(user['sub']) if not session.get('project') or not session.get( 'web_url') or not session.get('added_user'): init_project(user)
</head> <body> <script> window.opener.postMessage( "{token}", "{app.config['FRONTEND_URL']}" ); window.close(); </script> </body> </html> ''' oauth = OAuth(app) bp = create_flask_blueprint([Discord], oauth, handle_authorize) app.register_blueprint(bp, url_prefix='') @app.teardown_appcontext def shutdown_session(exception=None): db.remove() @app.before_first_request def start_db(): calcStats() def calcStats(): global solveCounts
User.create(remote.name, external_id, name, email, profile_pic, request.headers.get('CF-IPCountry') or 'XX') user = User.get_user_from_email(email) if user.identity_provider != remote.name: return redirect("/409") # TODO updte last_login date login_user(user) return redirect("/gallery") Hydra = create_hydra_backend("hydra", FOTRINO_HYDRA_HOST) bp = create_flask_blueprint([ Facebook, Google, GitHub, Reddit, Instagram, Gitlab, LinkedIn, StackOverflow, Hydra ], oauth, handle_authorize) app.register_blueprint(bp, url_prefix='/api/account') # Account Routes ############################################################## ############################################################################### @app.route("/api/account/providers", methods=['GET']) def get_oauth_providers(): return json.dumps(FOTRINO_OAUTH_PROVIDERS) @app.route("/api/account/profile", methods=['GET']) @login_required def get_profile():
def init_webapp(config, test=False): """Initialize the web application. Initializes and configures the Flask web application. Call this method to make the web application and respective database engine usable. If initialized with `test=True` the application will use an in-memory SQLite database, and should be used for unit testing, but not much else. """ # Make app work with proxies (like nginx) that set proxy headers. app.wsgi_app = ProxyFix(app.wsgi_app) # logging.getLogger('flask_cors').level = logging.DEBUG # Note, this url namespace also exists for the Flask-Restless extension and # is where CRUD interfaces live, so be careful not to collide with model # names here. We could change this, but it's nice to have API live in the # same url namespace. app.register_blueprint(api, url_prefix='/api') # Initialize Flask configuration if test: app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://' else: app.config['SQLALCHEMY_DATABASE_URI'] = config['webapp'][ 'database_uri'] # FIXME: Port these over to configobj. app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'abc123') app.config['SECURITY_TOKEN_MAX_AGE'] = 60 app.config['SECURITY_TOKEN_AUTHENTICATION_HEADER'] = 'Auth-Token' app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt' app.config['SECURITY_PASSWORD_SALT'] = os.environ.get('SALT', 'salt123') app.config['SECURITY_REGISTERABLE'] = True app.config['SECURITY_CONFIRMABLE'] = False app.config['SECURITY_SEND_REGISTER_EMAIL'] = False # This thing is a supreme PIA with API, and because we're using token based # authentication. app.config['WTF_CSRF_ENABLED'] = False # Initialize Flask-CORS CORS(app, supports_credentials=True) # CORS(app, supports_credentials=True, resources={r"/*": {"origins": "*"}}) # Initialize Flask-Bootstrap Bootstrap(app) # Initialize Flask-Security user_datastore = SQLAlchemyUserDatastore(db, User, Role) Security(app, user_datastore) app.config['GOOGLE_CLIENT_ID'] = os.environ.get('GOOGLE_CLIENT_ID', 'abc123') app.config['GOOGLE_CLIENT_SECRET'] = os.environ.get( 'GOOGLE_CLIENT_SECRET', 'password') app.config[ 'GOOGLE_REFRESH_TOKEN_URL'] = 'https://www.googleapis.com/oauth2/v4/token' app.config['GOOGLE_CLIENT_KWARGS'] = dict(scope=' '.join([ 'openid', 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/calendar.readonly', ])) # Initialize Authlib. oauth = OAuth() oauth.init_app(app, fetch_token=authlib_fetch_token, update_token=authlib_update_token) google_blueprint = create_flask_blueprint(Google, oauth, authlib_handle_authorize) app.register_blueprint(google_blueprint, url_prefix='/google') # Save the oauth object in the app so handlers can use it to build clients. app.oauth = oauth # Initialize Flask-SQLAlchemy db.app = app db.init_app(app) # NOTE: You don't want to use this if you're using alembic, since alembic # is now in charge of creating/upgrading/downgrading your database. If you # choose to not use alembic, you can add this line here. # db.create_all() # Initialize Flask-Restless manager = APIManager( app, flask_sqlalchemy_db=db, preprocessors=dict(GET_MANY=[restless_api_auth_func]), ) # manager.create_api(TableName methods=['GET', 'POST', 'OPTIONS']) return app
def __init__(self, register, libraries, settings): print("Start OAuth 2.0 Server") app = Flask(__name__) oauth = OAuth(app) github_bp = create_flask_blueprint(GitHub, oauth, self.handle_authorize) app.register_blueprint(github_bp, url_prefix='/github')
# If a 'next' URL is provided, then store it into the session # to redirect the user after the authorization is complete if 'next_url' in request.args: session['next_url'] = request.args.get('next_url') return render_template('index.html') def handle_authorize(remote, token, user_info): refresh_token_value = token['refresh_token'] encrypted_value = encrypt(settings.ENCRYPTION_REFRESH_TOKEN_CRYPTO_KEY, refresh_token_value) gcp_user = user_info['email'] validate_domain(gcp_user) # Save the refresh token refresh_token = RefreshToken(id=gcp_user, value=encrypted_value) refresh_token.save() # Retrieve next URL from the session, if any next_url = session.pop('next_url', None) return render_template('success.html', next_url=next_url) oauth = OAuth(app) bp = create_flask_blueprint(Google, oauth, handle_authorize) app.register_blueprint(bp, url_prefix='/google') if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)
return render_template('public/home.html', form=form) def handle_authorize(remote, token, user_info): email = user_info['email'] user = db.session.query(User).filter_by(email=email).first() if not user: User.create(username=user_info['name'], email=user_info['email'], active=True) else: return 'User exists' return redirect(url_for('public.home')) google_bp = create_flask_blueprint(Google, oauth, handle_authorize) github_bp = create_flask_blueprint(GitHub, oauth, handle_authorize) @blueprint.route('/logout/') @login_required def logout(): """Logout.""" logout_user() flash('You are logged out.', 'info') return redirect(url_for('public.home')) @blueprint.route('/register/', methods=['GET', 'POST']) def register(): """Register new user."""
# Bitbucket, Spotify, Strava ) # app imports from mjserver import app #%% oauth stuff OAUTH_BACKENDS = [ Discord, Google, # Twitter, Facebook, GitHub, Dropbox, # Reddit, Gitlab, Slack, StackOverflow, # Bitbucket, Strava, Spotify ] @app.route('/hid/') def oauth_login_list(): tpl = '<li><a href="/{}/login">{}</a></li>' lis = [tpl.format(b.OAUTH_NAME, b.OAUTH_NAME) for b in OAUTH_BACKENDS] return '<ul>{}</ul>'.format(''.join(lis)) def handle_authorize(remote, token, user_info): # type(remote) == RemoteApp # str(token) return str(user_info) oauth = OAuth(app) for backend in OAUTH_BACKENDS: bp = create_flask_blueprint(backend, oauth, handle_authorize) app.register_blueprint(bp, url_prefix='/{}'.format(backend.OAUTH_NAME))
def create_flask_application(self): application = Flask(__name__) gzip = Gzip(application) application.log = {} application.killurl = str(uuid.uuid4()) application.jinja_env.add_extension('jinja2.ext.do') application.config.update( SESSION_TYPE='filesystem', PERMANENT_SESSION_LIFETIME=60*15, # 15 min SECRET_KEY=self.secret_key, GITHUB_CLIENT_ID=self.client_id, GITHUB_CLIENT_SECRET=self.client_secret, GITHUB_CLIENT_KWARGS = { 'scope': 'repo' } ) Session(application) oauth = OAuth(application) github_bp = create_flask_blueprint(GitHub, oauth, handle_authorize) application.register_blueprint(github_bp, url_prefix='/github') @application.template_filter('remove_terms', ) def remove_terms(content, repository_configuration, word_boundaries=True, whole_urls=True): """ remove the blacklisted terms from the content :param content: the content to anonymize :param repository_configuration: the configuration of the repository :return: the anonymized content """ repo = repository_configuration['repository'] if repo[-1] == '/': repo = repo[0:-1] content = re.compile("%s/blob/master" % repo, re.IGNORECASE).sub( "%s/repository/%s" % (self.public_url, repository_configuration["id"]), content) content = re.compile(repo, re.IGNORECASE).sub("%s/repository/%s" % (self.public_url, repository_configuration["id"]), content) for term in repository_configuration['terms']: if word_boundaries: regex = re.compile(r'\b%s\b' % term, re.IGNORECASE) else: regex = re.compile(term, re.IGNORECASE) if whole_urls: def sub_url(m): if regex.search(m.group(0)): return 'XXX' return m.group(0) url_regex = re.compile('\\b((https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]\\b') content = url_regex.sub(sub_url, content) content = regex.sub("XXX", content) return content @application.template_filter('file_render', ) def file_render(file, repository_configuration): """ produce the html representation of a file :param file: the file to display :param repository_configuration: the configuration of the repository :return: the html representation of the file """ if type(file) == github.Commit.Commit: return Markup(remove_terms(render_template('patch.html', patch=file), repository_configuration)) if file.type == 'dir': return "" if file.size > 1000000: return Markup("The file %s is too big to be anonymized (beyond 1MB, Github limit)" % (file.name)) if ".md" in file.name or file.name == file.name.upper() or "changelog" == file.name.lower(): gh = self.github if 'token' in repository_configuration and repository_configuration['token'] is not None: gh = github.Github(repository_configuration['token']) return Markup("<div class='markdown-body'>%s</div>" % remove_terms( gh.render_markdown(file.decoded_content.decode('utf-8')), repository_configuration)) if ".jpg" in file.name or ".png" in file.name or ".png" in file.name or ".gif" in file.name: index = file.name.index('.') file_extension = file.name[index + 1:] return Markup("<img src='data:image/%s;base64, %s' alt='%s'>" % (file_extension, file.content, file.name)) if istext(file.decoded_content): return Markup("<pre><code>{}</code></pre>")\ .format(Markup.escape(remove_terms(file.decoded_content.decode("utf-8"), repository_configuration))) return Markup("<b>%s has an unknown extension, we are unable to anonymize it (known extensions md/txt/json/java/...)</b>" % (file.name)) @application.route('/' + application.killurl, methods=['POST']) def seriouslykill(): func = request.environ.get('werkzeug.server.shutdown') func() return "Shutting down..." def get_element_from_path(g_repo, g_commit, path): """ get a github element from its path :param g_repo: the github repository :param path: the path of the element :return: the element """ if path == '': return g_repo.get_contents('', g_commit.sha), None current_element = os.path.basename(path) folder_content = g_repo.get_contents(quote(os.path.dirname(path)), g_commit.sha) for file in folder_content: if file.name == current_element: return file, folder_content return None, folder_content @application.route('/myrepo', methods=['GET']) def myrepo(): user = session.get('user', None) if user is None or 'token' not in user or user['token'] is None: return redirect('github/login') g = github.Github(user['token']['access_token']) repos = g.get_user().get_repos(sort="full_name") for repo in repos: repo.uuid = str(uuid.uuid4()) return render_template('newrepo.html', repos=repos) @application.route('/repository/<id>/commit/<sha>', methods=['GET']) def commit(id, sha): """ display anonymously a commit from the repository :param id: the repository id :param sha: the commit id """ config_path = self.config_dir + "/" + str(id) + "/config.json" if not os.path.exists(config_path): return render_template('404.html'), 404 with open(config_path) as f: data = json.load(f, object_hook=json_util.object_hook) (username, repo, branch) = clean_github_repository(data['repository']) gh = self.github if 'token' in data: gh = github.Github(data['token']) g_repo = gh.get_repo("%s/%s" % (username, repo)) commit = g_repo.get_commit(sha) return render_template('repo.html', repository=data, current_repository=id, current_file=commit, files=[], path=[]) def is_up_to_date(repository_config, g_commit): """ check is the cache is up to date :param repository_config: the repository configuration :param g_commit: the Github commit :return: True if the cache is up to date """ commit_date = datetime.strptime(g_commit.last_modified, "%a, %d %b %Y %H:%M:%S %Z") return 'pushed_at' in repository_config and commit_date.strftime("%s") == repository_config["pushed_at"] def get_type_content(file_name, path, repository_configuration, g_repo, is_website): """ Get the content type of a file from its extension :param file_name: the filename :param path: the path of the file :param repository_configuration: the repository configuration :param g_repo: the Github repository :return: the content type """ if is_website: content_type = 'text/plain; charset=utf-8' if ".html" in file_name: content_type = 'text/html; charset=utf-8' if ".md" in file_name or file_name == file_name.upper(): content_type = 'text/html; charset=utf-8' if ".jpg" in file_name \ or ".png" in file_name \ or ".gif" in file_name: content_type = 'image/jpeg' if ".png" in file_name: content_type = 'image/png' elif ".gif" in file_name: content_type = 'image/gif' if ".txt" in file_name \ or ".log" in file_name \ or ".csv" in file_name \ or ".xml" in file_name \ or ".json" in file_name \ or ".java" in file_name \ or ".py" in file_name \ or ".lua" in file_name \ or ".js" in file_name: content_type = 'text/plain; charset=utf-8' if ".xml" in file_name: content_type = 'application/xml; charset=utf-8' elif ".json" in file_name: content_type = 'application/json; charset=utf-8' elif ".js" in file_name: content_type = 'application/javascript; charset=utf-8' if ".css" in file_name: content_type = 'text/css; charset=utf-8' return content_type return 'text/html; charset=utf-8' def get_content(current_file, files, path, repository_config, g_repo): """ get the content if the page :param current_file: the current file :param files: the list of file of the current directory :param path: the accessed path :param repository_config: the repository configuration :param g_repo: the Github repository :return: the content of the page """ cache_path = os.path.join(self.config_dir, repository_config['id'], "cache") file_path = path if current_file is not None: if current_file.type == 'dir': file_path = os.path.join(current_file.path, "index.html") else: file_path = current_file.path cached_file_path = os.path.join(cache_path, file_path) content_type = get_type_content(path, path, repository_config, g_repo, False).replace("; charset=utf-8", "") if os.path.exists(cached_file_path): return send_from_directory(os.path.dirname(cached_file_path), os.path.basename(cached_file_path), mimetype=content_type) content = '' if current_file.type != 'dir' and is_website(path, repository_config, g_repo): if current_file.size > 1000000: blob = g_repo.get_git_blob(current_file.sha) if blob.encoding == 'base64': content = base64.b64decode(blob.content).decode('utf-8') else: content = blob.content.decode('utf-8') else: content = current_file.decoded_content.decode('utf-8') if "text" in content_type: content = remove_terms(content, repository_config) if ".md" in current_file.name: gh = self.github if 'token' in repository_config: gh = github.Github(repository_config['token']) content = remove_terms(gh.render_markdown(content), repository_config) else: tree = files if type(tree) != list: tree = files.tree content = render_template('repo.html', repository=repository_config, current_repository=repository_config['id'], current_file=current_file, files=tree, path_directory=path if type( current_file) is not github.ContentFile.ContentFile or current_file.type == 'dir' else os.path.dirname( current_file.path), path=path.split("/") if path != '' else []) content_cache_path = cached_file_path if not os.path.exists(os.path.dirname(content_cache_path)): os.makedirs(os.path.dirname(content_cache_path)) with open(content_cache_path, 'w') as f: if type(content) == str: f.write(content) else: f.write(content.encode('utf8')) return content def is_website(path, repository_config, g_repo): """ Check if the current request is a request to a GitHub pages :param path: the current path :param repository_config: the repository configuration :param g_repo: the Github repository :return: True if the current path is a website """ return path[:4] == "docs" def is_default_file(f): default_name = ["readme", "index"] for name in default_name: try: if type(f) is github.ContentFile.ContentFile: f.name.lower().index(name) elif type(f) is github.GitTreeElement.GitTreeElement: f.path.lower().index(name) return True except ValueError: continue return False def get_current_folder_files(path, current_file, repository_config, g_repo, g_commit): """ get the list of files of the current repository :param path: the path to the current file :param current_file: the current file :param repository_config: the repository configuration :param g_repo: the GitHub repository :return: the list of file of the current repository """ files = [] if current_file is None: return files, current_file if type(current_file) is not github.ContentFile.ContentFile: files = g_repo.get_git_tree(g_commit.sha) for f in current_file: if is_default_file(f): current_file = f break if type(current_file) is not github.ContentFile.ContentFile: current_file = current_file[0] elif current_file.type == 'file': if os.path.dirname(path) == '': files = g_repo.get_git_tree(g_commit.sha) else: f, folder = get_element_from_path(g_repo, g_commit, os.path.dirname(path)) if f is None: files = folder else: files = g_repo.get_git_tree(f.sha) else: files = g_repo.get_git_tree(current_file.sha) for f in files.tree: if is_default_file(f): current_file, folder = get_element_from_path(g_repo, g_commit, os.path.join(path, f.path)) break if len(files.tree) == 1 and type(files.tree[0]) is github.ContentFile.ContentFile: current_file, folder = get_element_from_path(g_repo, g_commit, os.path.join(path, files.tree[0].path)) return files, current_file @application.route('/repository/<id>', methods=['GET'], defaults={'path': ''}) @application.route('/repository/<id>/', methods=['GET'], defaults={'path': ''}) @application.route('/repository/<id>/<path:path>', methods=['GET']) @application.route('/r/<id>', methods=['GET'], defaults={'path': ''}) @application.route('/r/<id>/', methods=['GET'], defaults={'path': ''}) @application.route('/r/<id>/<path:path>', methods=['GET']) def repository(id, path): repo_path = self.config_dir + "/" + str(id) config_path = repo_path + "/config.json" if not os.path.exists(config_path): return render_template('404.html'), 404 with open(config_path, 'r') as f: repository_configuration = json.load(f, object_hook=json_util.object_hook) if 'expiration_date' in repository_configuration and repository_configuration['expiration_date'] is not None: if repository_configuration['expiration_date'] <= datetime.now(repository_configuration['expiration_date'].tzinfo): if repository_configuration['expiration'] == 'redirect': return redirect(repository_configuration['repository']) elif repository_configuration['expiration'] == 'remove': return render_template('404.html'), 404 (username, repo, branch) = clean_github_repository(repository_configuration['repository']) gh = self.github if 'token' in repository_configuration and repository_configuration['token'] is not None: gh = github.Github(repository_configuration['token']) g_commit = None try: g_repo = gh.get_repo("%s/%s" % (username, repo)) if branch is None: branch = g_repo.default_branch g_commit = g_repo.get_commit(branch) except: return render_template('empty.html'), 404 if not is_up_to_date(repository_configuration, g_commit): if os.path.exists(os.path.join(repo_path, "cache")): shutil.rmtree(os.path.join(repo_path, "cache")) commit_date = datetime.strptime(g_commit.last_modified, "%a, %d %b %Y %H:%M:%S %Z") repository_configuration["pushed_at"] = commit_date.strftime("%s") with open(config_path, 'w') as fa: json.dump(repository_configuration, fa, default=json_util.default) cache_path = os.path.join(self.config_dir, id, "cache") if os.path.isfile(os.path.join(cache_path, path)): return send_from_directory(os.path.dirname(os.path.join(cache_path, path)), os.path.basename(os.path.join(cache_path, path)), mimetype=get_type_content(path, path, repository_configuration, g_repo, is_website(path, repository_configuration, g_repo)).replace("; charset=utf-8", "")) elif os.path.exists(os.path.join(cache_path, path, "index.html")): return send_from_directory(os.path.join(cache_path, path), "index.html", mimetype='text/html') elif os.path.exists(os.path.join(cache_path, path, "README.md")): return send_from_directory(os.path.join(cache_path, path), "README.md", mimetype='text/html') clean_path = path if len(clean_path) > 0 and clean_path[-1] == '/': clean_path = clean_path[0:-1] current_file, files = get_element_from_path(g_repo, g_commit, clean_path) if current_file is None: return render_template('404.html'), 404 if type(current_file) == github.ContentFile.ContentFile and current_file.type == 'dir' and len(path) > 0 and path[-1] != '/': return redirect(url_for('repository', id=id, path=path + '/')) files, current_file = get_current_folder_files(clean_path, current_file, repository_configuration, g_repo, g_commit) content = get_content(current_file, files, clean_path, repository_configuration, g_repo) content_type = get_type_content(current_file.name, clean_path, repository_configuration, g_repo, False) return content, {'Content-Type': content_type} @application.route('/', methods=['GET']) def index(): id = request.args.get('id', None) repo_name = clean_github_repository(request.args.get('githubRepository', None)) repo = None if id is not None: config_path = self.config_dir + "/" + id + "/config.json" if os.path.exists(config_path): with open(config_path) as f: data = json.load(f, object_hook=json_util.object_hook) if repo_name == clean_github_repository(data['repository']): repo = data return render_template('index.html', repo=repo) @application.route('/robots.txt') def robots(): return application.send_static_file('robots.txt') @application.route('/', methods=['POST']) def add_repository(): id = request.args.get('id', str(uuid.uuid4())) config_path = os.path.join(self.config_dir, str(id)) repo = request.form['githubRepository'] terms = request.form['terms'] expiration_date = None expiration = None if 'expiration' in request.form: expiration = request.form['expiration'] if 'expiration_date' in request.form and request.form['expiration_date'] != '': expiration_date = datetime.strptime(request.form['expiration_date'], '%Y-%m-%d') user = session.get('user', None) token = None if os.path.exists(config_path): with open(os.path.join(config_path, "config.json"), 'r') as r: data = json.load(r) if 'token' in data: token = data['token'] if token is None and user is not None and 'token' in user and user['token'] is not None: token = user['token']['access_token'] if not os.path.exists(config_path): os.mkdir(config_path) with open(config_path + "/config.json", 'w') as outfile: json.dump({ "id": id, "repository": repo, "terms": terms.splitlines(), "token": token, "expiration_date": expiration_date, "expiration": expiration }, outfile, default=json_util.default) return redirect(url_for('repository', id=id)) return application