Exemplo n.º 1
0
    def auth(self):
        # Start with an authentication request
        # The client ID appears in the request
        AUTH_REQ = AuthorizationRequest(
            client_id="client_1",
            redirect_uri="https://example.com/cb",
            scope=["openid", "mail", "address", "offline_access"],
            state="STATE",
            response_type="code",
        )

        # The authentication returns a user ID
        user_id = "diana"

        # User info is stored in the Session DB
        authn_event = create_authn_event(
            user_id,
            authn_info=INTERNETPROTOCOLPASSWORD,
            authn_time=time_sans_frac(),
        )

        user_info = UserSessionInfo(user_id=user_id)
        self.session_manager.set([user_id], user_info)

        # Now for client session information
        client_id = AUTH_REQ["client_id"]
        client_info = ClientSessionInfo(client_id=client_id)
        self.session_manager.set([user_id, client_id], client_info)

        # The user consent module produces a Grant instance

        grant = Grant(
            scope=AUTH_REQ["scope"],
            resources=[client_id],
            authorization_request=AUTH_REQ,
            authentication_event=authn_event,
        )

        # the grant is assigned to a session (user_id, client_id)
        self.session_manager.set([user_id, client_id, grant.id], grant)
        session_id = self.session_manager.encrypted_session_id(
            user_id, client_id, grant.id)

        # Constructing an authorization code is now done by

        code = grant.mint_token(
            session_id=session_id,
            endpoint_context=self.endpoint_context,
            token_class="authorization_code",
            token_handler=self.session_manager.
            token_handler["authorization_code"],
            expires_at=time_sans_frac() + 300,  # 5 minutes from now
        )

        # get user info
        user_info = self.session_manager.get_user_info(uid=user_id, )
        return grant.id, code
def test_authn_event():
    an = AuthnEvent(
        uid="uid",
        valid_until=time_sans_frac() + 1,
        authn_info="authn_class_ref",
    )

    assert an.is_valid()

    n = time_sans_frac() + 3
    assert an.is_valid(n) is False

    n = an.expires_in()
    assert n == 1  # could possibly be 0
Exemplo n.º 3
0
    def __call__(self,
                 session_id: Optional[str] = "",
                 token_class: Optional[str] = "",
                 **payload) -> str:
        """
        Return a token.

        :param payload: Token information
        :return:
        """
        if not token_class and self.token_class:
            token_class = self.token_class
        else:
            token_class = "authorization_code"

        if self.lifetime >= 0:
            exp = str(time_sans_frac() + self.lifetime)
        else:
            exp = "-1"  # Live for ever

        tmp = ""
        rnd = ""
        while rnd == tmp:  # Don't use the same random value again
            rnd = rndstr(32)  # Ultimate length multiple of 16

        return base64.b64encode(
            self.crypt.encrypt(
                lv_pack(rnd, token_class, session_id,
                        exp).encode())).decode("utf-8")
Exemplo n.º 4
0
    def process_request(self, request=None, **kwargs):
        _sdb = self.endpoint_context.sdb

        # should be an access token
        if not _sdb.is_token_valid(request["access_token"]):
            return self.error_cls(error="invalid_token",
                                  error_description="Invalid Token")

        session = _sdb.read(request["access_token"])

        allowed = True
        # if the authenticate is still active or offline_access is granted.
        if session["authn_event"]["valid_until"] > time_sans_frac():
            pass
        else:
            if "offline_access" in session["authn_req"]["scope"]:
                pass
            else:
                allowed = False

        if allowed:
            # Scope can translate to userinfo_claims
            info = collect_user_info(self.endpoint_context, session)
        else:
            info = {
                "error": "invalid_request",
                "error_description": "Offline access not granted",
            }

        return {
            "response_args": info,
            "client_id": session["authn_req"]["client_id"]
        }
Exemplo n.º 5
0
def create_authn_event(uid, salt, authn_info=None, **kwargs):
    """

    :param uid:
    :param salt:
    :param authn_info:
    :param kwargs:
    :return:
    """

    args = {'uid': uid, 'salt':salt, 'authn_info': authn_info}

    try:
        args['authn_time'] = int(kwargs['authn_time'])
    except KeyError:
        try:
            args['authn_time'] = int(kwargs['timestamp'])
        except KeyError:
            args['authn_time'] = time_sans_frac()

    try:
        args['valid_until'] = kwargs['valid_until']
    except KeyError:
        try:
            args['valid_until'] = args['authn_time'] + kwargs['expires_in']
        except KeyError:
            args['valid_until'] = args['authn_time'] + 3600

    return AuthnEvent(**args)
Exemplo n.º 6
0
def test_time_stamp():
    now = time_sans_frac()
    iso = to_iso8601_2004_time()

    d = from_iso8601_2004_time(iso)

    assert now == d
Exemplo n.º 7
0
    def __call__(self, sid='', ttype='', **kwargs):
        """
        Return a token.

        :param ttype: Type of token
        :param prev: Previous token, if there is one to go from
        :param sid: Session id
        :return:
        """
        if not ttype and self.type:
            ttype = self.type
        else:
            ttype = 'A'

        if self.lifetime >= 0:
            exp = str(time_sans_frac() + self.lifetime)
        else:
            exp = '-1'  # Live for ever

        tmp = ''
        rnd = ''
        while rnd == tmp:  # Don't use the same random value again
            rnd = rndstr(32)  # Ultimate length multiple of 16

        return base64.b64encode(
            self.crypt.encrypt(lv_pack(rnd, ttype, sid,
                                       exp).encode())).decode("utf-8")
Exemplo n.º 8
0
def create_authn_event(uid, salt, authn_info=None, **kwargs):
    """

    :param uid:
    :param salt:
    :param authn_info:
    :param kwargs:
    :return:
    """

    args = {"uid": uid, "salt": salt, "authn_info": authn_info}

    try:
        args["authn_time"] = int(kwargs["authn_time"])
    except KeyError:
        try:
            args["authn_time"] = int(kwargs["timestamp"])
        except KeyError:
            args["authn_time"] = time_sans_frac()

    try:
        args["valid_until"] = kwargs["valid_until"]
    except KeyError:
        try:
            args["valid_until"] = args["authn_time"] + kwargs["expires_in"]
        except KeyError:
            args["valid_until"] = args["authn_time"] + 3600

    return AuthnEvent(**args)
Exemplo n.º 9
0
def is_expired(exp, when=0):
    if exp < 0:
        return False

    if not when:
        when = time_sans_frac()
    return when > exp
Exemplo n.º 10
0
    def test_is_expired(self):
        session_id = self._create_session(AUTH_REQ)
        grant = self.session_manager[session_id]
        code = self._mint_token("authorization_code", grant, session_id)
        access_token = self._mint_token("access_token", grant, session_id,
                                        code)

        assert access_token.is_active()
        # 4000 seconds in the future. Passed the lifetime.
        assert access_token.is_active(now=time_sans_frac() + 4000) is False
Exemplo n.º 11
0
 def _mint_code(self, grant, session_id):
     # Constructing an authorization code is now done
     return grant.mint_token(
         session_id=session_id,
         endpoint_context=self.endpoint_context,
         token_class="authorization_code",
         token_handler=self.session_manager.
         token_handler["authorization_code"],
         expires_at=time_sans_frac() + 300,  # 5 minutes from now
     )
Exemplo n.º 12
0
 def _mint_access_token(self, grant, session_id, token_ref):
     access_token = grant.mint_token(
         session_id=session_id,
         endpoint_context=self.endpoint_context,
         token_class="access_token",
         token_handler=self.session_manager.token_handler["access_token"],
         expires_at=time_sans_frac() + 900,  # 15 minutes from now
         based_on=
         token_ref,  # Means the token (tok) was used to mint this token
     )
     return access_token
Exemplo n.º 13
0
 def _mint_token(self, token_class, grant, session_id, based_on=None):
     # Constructing an authorization code is now done
     return grant.mint_token(
         session_id=session_id,
         endpoint_context=self.endpoint_context,
         token_class=token_class,
         token_handler=self.session_manager.token_handler.
         handler[token_class],
         expires_at=time_sans_frac() + 300,  # 5 minutes from now
         based_on=based_on,
     )
Exemplo n.º 14
0
 def _mint_token(self, token_class, grant, session_id, token_ref=None):
     _session_info = self.session_manager.get_session_info(session_id,
                                                           grant=True)
     return grant.mint_token(
         session_id=session_id,
         endpoint_context=self.endpoint.server_get("endpoint_context"),
         token_class=token_class,
         token_handler=self.session_manager.token_handler[token_class],
         expires_at=time_sans_frac() + 900,  # 15 minutes from now
         based_on=
         token_ref,  # Means the token (tok) was used to mint this token
     )
Exemplo n.º 15
0
    def _mint_token(
        self,
        token_class: str,
        grant: Grant,
        session_id: str,
        client_id: str,
        based_on: Optional[SessionToken] = None,
        scope: Optional[list] = None,
        token_args: Optional[dict] = None,
        token_type: Optional[str] = ""
    ) -> SessionToken:
        _context = self.endpoint.server_get("endpoint_context")
        _mngr = _context.session_manager
        usage_rules = grant.usage_rules.get(token_class)
        if usage_rules:
            _exp_in = usage_rules.get("expires_in")
        else:
            _exp_in = 0

        token_args = token_args or {}
        for meth in _context.token_args_methods:
            token_args = meth(_context, client_id, token_args)

        if token_args:
            _args = {"token_args": token_args}
        else:
            _args = {}

        token = grant.mint_token(
            session_id,
            endpoint_context=_context,
            token_class=token_class,
            token_handler=_mngr.token_handler[token_class],
            based_on=based_on,
            usage_rules=usage_rules,
            scope=scope,
            token_type=token_type,
            **_args,
        )

        if _exp_in:
            if isinstance(_exp_in, str):
                _exp_in = int(_exp_in)

            if _exp_in:
                token.expires_at = time_sans_frac() + _exp_in

        _context.session_manager.set(_context.session_manager.unpack_session_key(session_id), grant)

        return token
Exemplo n.º 16
0
 def _mint_id_token(self,
                    grant,
                    session_id,
                    token_ref=None,
                    code=None,
                    access_token=None):
     return grant.mint_token(
         session_id=session_id,
         endpoint_context=self.endpoint_context,
         token_class="id_token",
         token_handler=self.session_manager.token_handler["id_token"],
         expires_at=time_sans_frac() + 900,  # 15 minutes from now
         based_on=
         token_ref,  # Means the token (tok) was used to mint this token
         code=code,
         access_token=access_token,
     )
Exemplo n.º 17
0
    def get_valid_access_token(self, state):
        """
        Find me a valid access token

        :param state:
        :return: An access token if a valid one exists and when it
            expires. Otherwise raise exception.
        """

        exp = 0
        token = None
        indefinite = []
        now = time_sans_frac()

        for cls, typ in [(AccessTokenResponse, 'refresh_token_response'),
                         (AccessTokenResponse, 'token_response'),
                         (AuthorizationResponse, 'auth_response')]:
            try:
                response = self.session_interface.get_item(cls, typ, state)
            except KeyError:
                pass
            else:
                try:
                    access_token = response['access_token']
                except:
                    continue
                else:
                    try:
                        _exp = response['__expires_at']
                    except KeyError:  # No expiry date, lives for ever
                        indefinite.append((access_token, 0))
                    else:
                        if _exp > now:  # expires sometime in the future
                            if _exp > exp:
                                exp = _exp
                                token = (access_token, _exp)

        if indefinite:
            return indefinite[0]
        else:
            if token:
                return token
            else:
                raise OidcServiceError('No valid access token')
Exemplo n.º 18
0
    def has_active_authentication(self, state):
        """
        Find out if the user has an active authentication

        :param state:
        :return: True/False
        """

        # Look for Id Token in all the places where it can be
        _arg = self.session_interface.multiple_extend_request_args(
            {}, state, ['__verified_id_token'],
            ['auth_response', 'token_response', 'refresh_token_response'])

        if _arg:
            _now = time_sans_frac()
            exp = _arg['__verified_id_token']['exp']
            return _now < exp
        else:
            return False
    def update_service_context(self, resp, key='', **kwargs):
        try:
            _idt = resp[verified_claim_name('id_token')]
        except KeyError:
            pass
        else:
            # If there is a verified ID Token then we have to do nonce
            # verification
            try:
                if self.get_state_by_nonce(_idt['nonce']) != key:
                    raise ParameterError('Someone has messed with "nonce"')
            except KeyError:
                raise ValueError('Missing nonce value')

            self.store_sub2state(_idt['sub'], key)

        if 'expires_in' in resp:
            resp['__expires_at'] = time_sans_frac() + int(resp['expires_in'])
        self.store_item(resp.to_json(), 'auth_response', key)
Exemplo n.º 20
0
    def is_active(self, now=0):
        if self.max_usage_reached():
            return False

        if self.revoked:
            return False

        if now == 0:
            now = time_sans_frac()

        if self.not_before:
            if now < self.not_before:
                return False

        if self.expires_at:
            if now > self.expires_at:
                return False

        return True
Exemplo n.º 21
0
    def update_service_context(self, resp, key='', **kwargs):
        try:
            _idt = resp[verified_claim_name('id_token')]
        except KeyError:
            pass
        else:
            try:
                if self.get_state_by_nonce(_idt['nonce']) != key:
                    raise ParameterError('Someone has messed with "nonce"')
            except KeyError:
                raise ValueError('Invalid nonce value')

            self.store_sub2state(_idt['sub'], key)

        if 'expires_in' in resp:
            resp['__expires_at'] = time_sans_frac() + int(
                resp['expires_in'])

        self.store_item(resp, 'token_response', key)
Exemplo n.º 22
0
def create_authn_event(uid,
                       authn_info=None,
                       authn_time: int = 0,
                       valid_until: int = 0,
                       expires_in: int = 0,
                       sub: str = "",
                       **kwargs):
    """

    :param uid: User ID. This is the identifier used by the user DB
    :param authn_time: When the authentication took place
    :param authn_info: Information about the authentication
    :param valid_until: Until when the authentication is valid
    :param expires_in: How long before the authentication expires
    :param sub: Subject identifier. The identifier for the user used between
        the AS and the RP.
    :param kwargs:
    :return:
    """
    args = {"uid": uid, "authn_info": authn_info}

    if sub:
        args["sub"] = sub

    if authn_time:
        args["authn_time"] = authn_time
    else:
        _ts = kwargs.get("timestamp")
        if _ts:
            args["authn_time"] = _ts
        else:
            args["authn_time"] = time_sans_frac()

    if valid_until:
        args["valid_until"] = valid_until
    else:
        if expires_in:
            args["valid_until"] = args["authn_time"] + expires_in
        else:
            args["valid_until"] = args["authn_time"] + DEFAULT_AUTHN_EXPIRES_IN

    return AuthnEvent(**args)
Exemplo n.º 23
0
    def test_invalid_token(self):
        _auth_req = AUTH_REQ.copy()
        _auth_req["scope"] = ["openid", "research_and_scholarship"]

        session_id = self._create_session(_auth_req)
        grant = self.session_manager[session_id]
        access_token = self._mint_token("access_token", grant, session_id)

        http_info = {
            "headers": {
                "authorization": "Bearer {}".format(access_token.value)
            }
        }
        _req = self.endpoint.parse_request({}, http_info=http_info)

        access_token.expires_at = time_sans_frac() - 10
        args = self.endpoint.process_request(_req)

        assert isinstance(args, ResponseMessage)
        assert args["error_description"] == "Invalid Token"
Exemplo n.º 24
0
    def __init__(
        self,
        usage_rules: Optional[dict] = None,
        issued_at: int = 0,
        expires_in: int = 0,
        expires_at: int = 0,
        not_before: int = 0,
        revoked: bool = False,
        used: int = 0,
    ):
        ImpExp.__init__(self)
        self.issued_at = issued_at or time_sans_frac()
        self.not_before = not_before
        if expires_at == 0 and expires_in != 0:
            self.set_expires_at(expires_in)
        else:
            self.expires_at = expires_at

        self.revoked = revoked
        self.used = used
        self.usage_rules = usage_rules or {}
Exemplo n.º 25
0
 def is_valid(self, now=0):
     if now:
         return self["valid_until"] > now
     else:
         return self["valid_until"] > time_sans_frac()
Exemplo n.º 26
0
 def expires_in(self):
     return self["valid_until"] - time_sans_frac()
Exemplo n.º 27
0
    def test_code_flow(self):
        # code is a Token instance
        code = self.auth()

        # next step is access token request

        TOKEN_REQ = AccessTokenRequest(
            client_id="client_1",
            redirect_uri="https://example.com/cb",
            state="STATE",
            grant_type="authorization_code",
            client_secret="hemligt",
            code=code.value,
        )

        # parse the token
        session_id = self.session_manager.token_handler.sid(TOKEN_REQ["code"])
        user_id, client_id, grant_id = self.session_manager.decrypt_session_id(
            session_id)

        # Now given I have the client_id from the request and the user_id from the
        # token I can easily find the grant

        # client_info = self.session_manager.get([user_id, TOKEN_REQ['client_id']])
        tok = self.session_manager.find_token(session_id, TOKEN_REQ["code"])

        # Verify that it's of the correct type and can be used
        assert tok.token_class == "authorization_code"
        assert tok.is_active()

        # Mint an access token and a refresh token and mark the code as used

        assert tok.supports_minting("access_token")

        client_info = self.session_manager.get(
            [user_id, TOKEN_REQ["client_id"]])

        assert tok.supports_minting("access_token")

        grant = self.session_manager[session_id]

        grant.mint_token(
            session_id=session_id,
            endpoint_context=self.endpoint_context,
            token_class="access_token",
            token_handler=self.session_manager.token_handler["access_token"],
            expires_at=time_sans_frac() + 900,  # 15 minutes from now
            based_on=tok,  # Means the token (tok) was used to mint this token
        )

        # this test is include in the mint_token methods
        # assert tok.supports_minting("refresh_token")

        refresh_token = grant.mint_token(
            session_id=session_id,
            endpoint_context=self.endpoint_context,
            token_class="refresh_token",
            token_handler=self.session_manager.token_handler["refresh_token"],
            based_on=tok,
        )

        tok.register_usage()

        assert tok.max_usage_reached() is True

        # A bit later a refresh token is used to mint a new access token

        REFRESH_TOKEN_REQ = RefreshAccessTokenRequest(
            grant_type="refresh_token",
            client_id="client_1",
            client_secret="hemligt",
            refresh_token=refresh_token.value,
            scope=["openid", "mail", "offline_access"],
        )

        session_id = self.session_manager.encrypted_session_id(
            user_id, REFRESH_TOKEN_REQ["client_id"], grant_id)
        reftok = self.session_manager.find_token(
            session_id, REFRESH_TOKEN_REQ["refresh_token"])

        # Can I use this token to mint another token ?
        assert grant.is_active()

        user_claims = self.endpoint_context.userinfo(
            user_id,
            client_id=TOKEN_REQ["client_id"],
            user_info_claims=grant.claims)

        access_token_2 = grant.mint_token(
            session_id=session_id,
            endpoint_context=self.endpoint_context,
            token_class="access_token",
            token_handler=self.session_manager.token_handler["access_token"],
            expires_at=time_sans_frac() + 900,  # 15 minutes from now
            based_on=
            reftok,  # Means the refresh token (reftok) was used to mint this token
        )

        assert access_token_2.is_active()

        token_info = self.session_manager.token_handler.info(
            access_token_2.value)
        assert token_info
Exemplo n.º 28
0
 def create_session_manager(self):
     conf = {
         "issuer": "https://example.com/",
         "password": "******",
         "token_expires_in": 600,
         "grant_expires_in": 300,
         "refresh_token_expires_in": 86400,
         "verify_ssl": False,
         "keys": {
             "key_defs": KEYDEFS,
             "uri_path": "static/jwks.json"
         },
         "jwks_uri": "https://example.com/jwks.json",
         "token_handler_args": {
             "jwks_def": {
                 "private_path":
                 "private/token_jwks.json",
                 "read_only":
                 False,
                 "key_defs": [{
                     "type": "oct",
                     "bytes": "24",
                     "use": ["enc"],
                     "kid": "code"
                 }],
             },
             "code": {
                 "lifetime": 600
             },
             "token": {
                 "class": "oidcop.token.jwt_token.JWTToken",
                 "kwargs": {
                     "lifetime": 3600,
                     "add_claims": True,
                     "add_claim_by_scope": True,
                     "aud": ["https://example.org/appl"],
                 },
             },
             "refresh": {
                 "class": "oidcop.token.jwt_token.JWTToken",
                 "kwargs": {
                     "lifetime": 3600,
                     "aud": ["https://example.org/appl"],
                 },
             },
         },
         "endpoint": {
             "authorization_endpoint": {
                 "path": "{}/authorization",
                 "class": Authorization,
                 "kwargs": {},
             },
             "token_endpoint": {
                 "path": "{}/token",
                 "class": Token,
                 "kwargs": {}
             },
         },
         "template_dir": "template",
         "claims_interface": {
             "class": "oidcop.session.claims.ClaimsInterface",
             "kwargs": {}
         },
     }
     server = Server(conf)
     self.server = server
     self.endpoint_context = server.endpoint_context
     self.session_manager = server.endpoint_context.session_manager
     self.authn_event = AuthnEvent(uid="uid",
                                   valid_until=time_sans_frac() + 1,
                                   authn_info="authn_class_ref")
     self.dummy_session_id = self.session_manager.encrypted_session_id(
         "user_id", "client_id", "grant.id")
Exemplo n.º 29
0
 def set_expires_at(self, expires_in):
     self.expires_at = time_sans_frac() + expires_in
Exemplo n.º 30
0
 def update_service_context(self, resp, key='cc', **kwargs):
     if 'expires_in' in resp:
         resp['__expires_at'] = time_sans_frac() + int(resp['expires_in'])
     self.store_item(resp, 'token_response', key)