Exemple #1
0
    def login(self, path=None):
        """
        EXPECT AN ACCESS TOKEN, RETURN A SESSION TOKEN
        """
        now = Date.now().unix
        try:
            access_token = get_token_auth_header()
            # if access_token.error:
            #     Log.error("{{error}}: {{error_description}}", access_token)
            if len(access_token.split(".")) == 3:
                access_details = self.verify_jwt_token(access_token)
                session.scope = access_details["scope"]

            # ADD TO SESSION
            self.session_manager.setup_session(session)
            user_details = self.verify_opaque_token(access_token)
            session.user = self.permissions.get_or_create_user(user_details)
            session.last_used = now

            self.markup_user()

            return Response(value2json(
                self.session_manager.make_cookie(session)),
                            status=200)
        except Exception as e:
            session.user = None
            session.last_used = None
            Log.error("failure to authorize", cause=e)
Exemple #2
0
    def verify_jwt_token(self, token):
        jwks = http.get_json("https://" + self.auth0.domain +
                             "/.well-known/jwks.json")
        unverified_header = jwt.get_unverified_header(token)
        algorithm = unverified_header["alg"]
        if algorithm != "RS256":
            Log.error("Expecting a RS256 signed JWT Access Token")

        key_id = unverified_header["kid"]
        key = unwrap(first(key for key in jwks["keys"]
                           if key["kid"] == key_id))
        if not key:
            Log.error("could not find {{key}}", key=key_id)

        try:
            return jwt.decode(
                token,
                key,
                algorithms=algorithm,
                audience=self.auth0.api.identifier,
                issuer="https://" + self.auth0.domain + "/",
            )
        except jwt.ExpiredSignatureError as e:
            Log.error("Token has expired", code=403, cause=e)
        except jwt.JWTClaimsError as e:
            Log.error(
                "Incorrect claims, please check the audience and issuer",
                code=403,
                cause=e,
            )
        except Exception as e:
            Log.error("Problem parsing", cause=e)
Exemple #3
0
    def get_subscriber(self, name=None):
        """
        GET SUBSCRIBER BY id, OR BY QUEUE name
        """
        with self.db.transaction() as t:
            result = t.query(
                SQL(
                    f"""
                    SELECT
                        MIN(s.id) as id
                    FROM
                        {SUBSCRIBER} AS s
                    LEFT JOIN 
                        {QUEUE} as q on q.id = s.queue
                    WHERE
                        q.name = {quote_value(name)}
                    GROUP BY 
                        s.queue
                    """
                )
            )
            if not result:
                Log.error("not expected")

            queue = self.get_or_create_queue(name)
            sub_info = t.query(
                sql_query(
                    {"from": SUBSCRIBER, "where": {"eq": {"id": first_row(result).id}}}
                )
            )

            return Subscription(queue=queue, kwargs=first_row(sub_info))
Exemple #4
0
    def output(*args, **kwargs):
        # IS THIS A NEW SESSION
        now = Date.now().unix
        user = session.get("user")
        if not user:
            Log.error("must authorize first")

        session.last_used = now
        return func(*args, user=user, **kwargs)
Exemple #5
0
def get_token_auth_header():
    """Obtains the Access Token from the Authorization Header
    """
    try:
        auth = request.headers.get("Authorization", None)
        bearer, token = auth.split()
        if bearer.lower() == "bearer":
            return token
    except Exception as e:
        pass
    Log.error('Expecting "Authorization = Bearer <token>" in header')
Exemple #6
0
def private_scoped(user):
    """A valid access token and an appropriate scope are required to access this route
    """
    if requires_scope(config.auth0.scope):
        response = (
            "Hello from a private endpoint! You need to be authenticated and have a scope of "
            + config.auth0.scope
            + " to see this."
        )
        return jsonify(message=response)
    Log.error("You don't have access to {{scope}}", scope=config.auth0.scope, code=403)
Exemple #7
0
def annotation():
    if flask.request.headers.get("content-length", "") in ["", "0"]:
        # ASSUME A BROWSER HIT THIS POINT, SEND text/html RESPONSE BACK
        return Response(ERROR_CONTENT,
                        status=400,
                        headers={"Content-Type": "text/html"})
    elif int(flask.request.headers["content-length"]) > QUERY_SIZE_LIMIT:
        Log.error("Query is too large to parse")

    request_body = flask.request.get_data().strip()
    text = utf82unicode(request_body)
    data = json2value(text)

    try:
        record_request(flask.request, data, None, None)
    except Exception as e:
        Log.error("Problem processing request {{request}}")
Exemple #8
0
    def __init__(self,
                 flask_app,
                 auth0,
                 permissions,
                 session_manager,
                 device=None):
        if not auth0.domain:
            Log.error("expecting auth0 configuration")

        self.auth0 = auth0
        self.permissions = permissions
        self.session_manager = session_manager

        # ATTACH ENDPOINTS TO FLASK APP
        endpoints = auth0.endpoints
        if not endpoints.login or not endpoints.logout or not endpoints.keep_alive:
            Log.error("Expecting paths for login, logout and keep_alive")

        add_flask_rule(flask_app, endpoints.login, self.login)
        add_flask_rule(flask_app, endpoints.logout, self.logout)
        add_flask_rule(flask_app, endpoints.keep_alive, self.keep_alive)

        if device:
            self.device = device
            db = self.device.db = Sqlite(device.db)
            if not db.about("device"):
                with db.transaction() as t:
                    t.execute(
                        sql_create(
                            "device",
                            {
                                "state": "TEXT PRIMARY KEY",
                                "session_id": "TEXT"
                            },
                        ))
            if device.auth0.redirect_uri != text_type(
                    URL(device.home, path=device.endpoints.callback)):
                Log.error(
                    "expecting home+endpoints.callback == auth0.redirect_uri")

            add_flask_rule(flask_app, device.endpoints.register,
                           self.device_register)
            add_flask_rule(flask_app, device.endpoints.status,
                           self.device_status)
            add_flask_rule(flask_app, device.endpoints.login,
                           self.device_login)
            add_flask_rule(flask_app, device.endpoints.callback,
                           self.device_callback)
Exemple #9
0
 def logout(self, path=None):
     if not session.session_id:
         Log.error("Expecting a sesison token")
     session.user = None
     session.last_used = None
     return Response(status=200)
Exemple #10
0
 def keep_alive(self, path=None):
     if not session.session_id:
         Log.error("Expecting a sesison token")
     now = Date.now().unix
     session.last_used = now
     return Response(status=200)
Exemple #11
0
    def device_callback(self, path=None):
        # HANDLE BROWESR RETURN FROM AUTH0 LOGIN
        error = request.args.get("error")
        if error:
            Log.error("You did it wrong")

        code = request.args.get("code")
        state = request.args.get("state")
        referer = request.headers.get("Referer")
        result = self.device.db.query(
            sql_query({
                "from": "device",
                "select": "session_id",
                "where": {
                    "eq": {
                        "state": state
                    }
                },
            }))
        if not result.data:
            Log.error("expecting valid state")
        device_session_id = result.data[0][0]

        # GO BACK TO AUTH0 TO GET TOKENS
        token_request = {
            "client_id": self.device.auth0.client_id,
            "redirect_uri": self.device.auth0.redirect_uri,
            "code_verifier": session.code_verifier,
            "code": code,
            "grant_type": "authorization_code",
        }
        DEBUG and Log.note("Send token request to Auth0:\n {{request}}",
                           request=token_request)
        auth_response = requests.request(
            "POST",
            str(URL("https://" + self.device.auth0.domain,
                    path="oauth/token")),
            headers={
                "Accept": "application/json",
                "Content-Type": "application/json",
                # "Referer": str(URL(self.device.auth0.redirect_uri, query={"code": code, "state": state})),
            },
            data=value2json(token_request),
        )

        try:
            auth_result = wrap(auth_response.json())
        except Exception as e:
            Log.error("not json {{value}}",
                      value=auth_response.content,
                      cause=e)

        # VERIFY TOKENS, ADD USER TO DEVICE'S SESSION
        user_details = self.verify_opaque_token(auth_result.access_token)
        self.session_manager.update_session(
            device_session_id,
            {"user": self.permissions.get_or_create_user(user_details)},
        )

        # REMOVE DEVICE SETUP STATE
        with self.device.db.transaction() as t:
            t.execute(SQL_DELETE + SQL_FROM + quote_column(self.device.table) +
                      SQL_WHERE + sql_eq(state=state))
        Log.note("login complete")
        return Response("Login complete. You may close this page", status=200)
Exemple #12
0
 def delete_queue(self, name):
     Log.error("You do not need to do this")