Exemple #1
0
def generate_id_token(
        token, user_info, key, iss, aud, alg='RS256', exp=3600,
        nonce=None, auth_time=None, code=None):

    now = int(time.time())
    if auth_time is None:
        auth_time = now

    payload = {
        'iss': iss,
        'aud': aud,
        'iat': now,
        'exp': now + exp,
        'auth_time': auth_time,
    }
    if nonce:
        payload['nonce'] = nonce

    if code:
        payload['c_hash'] = to_native(create_half_hash(code, alg))

    access_token = token.get('access_token')
    if access_token:
        payload['at_hash'] = to_native(create_half_hash(access_token, alg))

    payload.update(user_info)
    return to_native(jwt.encode({'alg': alg}, payload, key))
Exemple #2
0
def _generate_id_token_payload(alg,
                               iss,
                               aud,
                               exp,
                               nonce=None,
                               auth_time=None,
                               code=None,
                               access_token=None):
    now = int(time.time())
    if auth_time is None:
        auth_time = now

    payload = {
        'iss': iss,
        'aud': aud,
        'iat': now,
        'exp': now + exp,
        'auth_time': auth_time,
    }
    if nonce:
        payload['nonce'] = nonce

    if code:
        payload['c_hash'] = to_native(create_half_hash(code, alg))

    if access_token:
        payload['at_hash'] = to_native(create_half_hash(access_token, alg))
    return payload
Exemple #3
0
    def generate_id_token(self,
                          token,
                          request,
                          nonce=None,
                          auth_time=None,
                          code=None):
        scopes = scope_to_list(token['scope'])
        if not scopes or scopes[0] != 'openid':
            return None

        # TODO: merge scopes and claims
        user_info = self.generate_user_info(request.user, scopes)

        now = int(time.time())
        if auth_time is None:
            auth_time = now

        config = self.server.config
        payload = {
            'iss': config['jwt_iss'],
            'aud': [request.client.client_id],
            'iat': now,
            'exp': now + config['jwt_exp'],
            'auth_time': auth_time,
        }
        if nonce:
            payload['nonce'] = nonce

        # calculate at_hash
        alg = config['jwt_alg']

        access_token = token.get('access_token')
        if access_token:
            payload['at_hash'] = to_native(create_half_hash(access_token, alg))

        # calculate c_hash
        if code:
            payload['c_hash'] = to_native(create_half_hash(code, alg))

        payload.update(user_info)
        jwt = JWT(algorithms=alg)
        header = {'alg': alg}

        key = config['jwt_key']
        if isinstance(key, dict):
            # JWK set format
            if 'keys' in key:
                key = random.choice(key['keys'])
                header['kid'] = key['kid']
            elif 'kid' in key:
                header['kid'] = key['kid']

        return to_native(jwt.encode(header, payload, key))
Exemple #4
0
    def generate(self,
                 grant_type,
                 client,
                 user=None,
                 scope=None,
                 expires_in=None):
        """Generate a bearer token for OAuth 2.0 authorization token endpoint.

        :param client: the client that making the request.
        :param grant_type: current requested grant_type.
        :param user: current authorized user.
        :param expires_in: if provided, use this value as expires_in.
        :param scope: current requested scope.
        :return: Token dict
        """
        token_data = self.get_token_data(grant_type, client, user, scope,
                                         expires_in)
        access_token = jwt.encode({'alg': self.alg},
                                  token_data,
                                  key=self.secret_key,
                                  check=False)
        token = {
            'token_type': 'Bearer',
            'access_token': to_native(access_token),
            'expires_in': expires_in
        }
        if scope:
            token['scope'] = scope
        return token
Exemple #5
0
    def __call__(self, req):
        """Add OAuth parameters to the request.

        Parameters may be included from the body if the content-type is
        urlencoded, if no content type is set a guess is made.
        """
        # Overwriting url is safe here as request will not modify it past
        # this point.

        content_type = to_native(req.headers.get('Content-Type', ''))
        if self.signature_type == SIGNATURE_TYPE_BODY:
            content_type = CONTENT_TYPE_FORM_URLENCODED
        elif not content_type and extract_params(req.body):
            content_type = CONTENT_TYPE_FORM_URLENCODED

        if CONTENT_TYPE_FORM_URLENCODED in content_type:
            req.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED
            req.url, headers, req.body = self.sign_request(req)
        elif self.force_include_body:
            # To allow custom clients to work on non form encoded bodies.
            req.url, headers, req.body = self.sign_request(req)
        else:
            # Omit body data in the signing of non form-encoded requests
            req.url, headers, _ = self.sign(
                req.method, req.url, '', req.headers)

        req.prepare_headers(headers)
        req.url = to_native_string(req.url)
        return req
Exemple #6
0
    def wrap(self, cek, headers, key):
        self._check_key(key)

        #: https://tools.ietf.org/html/rfc7518#section-4.7.1.1
        #: The "iv" (initialization vector) Header Parameter value is the
        #: base64url-encoded representation of the 96-bit IV value
        iv_size = 96
        iv = os.urandom(iv_size // 8)

        cipher = Cipher(AES(key), GCM(iv), backend=default_backend())
        enc = cipher.encryptor()
        ek = enc.update(cek) + enc.finalize()

        h = {
            'iv': to_native(urlsafe_b64encode(iv)),
            'tag': to_native(urlsafe_b64encode(enc.tag))
        }
        return {'ek': ek, 'header': h}
Exemple #7
0
    def __call__(self, req):
        url, headers, body = self.prepare(req.method, req.url, req.headers,
                                          req.body)

        req.url = to_native(url)
        req.prepare_headers(headers)
        if body:
            req.body = body
        return req
Exemple #8
0
    def generate_id_token(self, token, request, nonce=None,
                          auth_time=None, code=None):

        scopes = scope_to_list(token['scope'])
        if not scopes or scopes[0] != 'openid':
            return None

        # TODO: merge scopes and claims
        user_info = self.generate_user_info(request.user, scopes)

        now = int(time.time())
        if auth_time is None:
            auth_time = now

        config = self.server.config
        payload = {
            'iss': config['jwt_iss'],
            'aud': [request.client.client_id],
            'iat': now,
            'exp': now + token['expires_in'],
            'auth_time': auth_time,
        }
        if nonce:
            payload['nonce'] = nonce

        # calculate at_hash
        alg = config.get('jwt_alg', 'HS256')

        access_token = token.get('access_token')
        if access_token:
            at_hash = to_native(create_half_hash(access_token, alg))
            payload['at_hash'] = at_hash

        # calculate c_hash
        if code:
            payload['c_hash'] = to_native(create_half_hash(code, alg))

        payload.update(user_info)
        jwt = JWT(algorithms=alg)
        header = {'alg': alg}
        key = config['jwt_key']
        id_token = jwt.encode(header, payload, key)
        return to_native(id_token)
Exemple #9
0
def _jwt_encode(alg, payload, key):
    jwt = JWT(algorithms=alg)
    header = {'alg': alg}
    if isinstance(key, dict):
        # JWK set format
        if 'keys' in key:
            key = random.choice(key['keys'])
            header['kid'] = key['kid']
        elif 'kid' in key:
            header['kid'] = key['kid']

    return to_native(jwt.encode(header, payload, key))
Exemple #10
0
    def wrap(self, enc_alg, headers, key, preset=None):
        if preset and 'cek' in preset:
            cek = preset['cek']
        else:
            cek = enc_alg.generate_cek()

        op_key = key.get_op_key('wrapKey')
        self._check_key(op_key)

        #: https://tools.ietf.org/html/rfc7518#section-4.7.1.1
        #: The "iv" (initialization vector) Header Parameter value is the
        #: base64url-encoded representation of the 96-bit IV value
        iv_size = 96
        iv = os.urandom(iv_size // 8)

        cipher = Cipher(AES(op_key), GCM(iv), backend=default_backend())
        enc = cipher.encryptor()
        ek = enc.update(cek) + enc.finalize()

        h = {
            'iv': to_native(urlsafe_b64encode(iv)),
            'tag': to_native(urlsafe_b64encode(enc.tag))
        }
        return {'ek': ek, 'cek': cek, 'header': h}
Exemple #11
0
    def refresh_token(self):
        """Using Assertions as Authorization Grants to refresh token as
        described in `Section 4.1`_.

        .. _`Section 4.1`: https://tools.ietf.org/html/rfc7521#section-4.1
        """
        generate_assertion = self.ASSERTION_METHODS[self.grant_type]
        assertion = generate_assertion(issuer=self.issuer,
                                       subject=self.subject,
                                       audience=self.audience,
                                       claims=self.claims,
                                       **self._kwargs)
        data = {
            'assertion': to_native(assertion),
            'grant_type': self.grant_type,
        }
        if self.scope:
            data['scope'] = self.scope

        return self._refresh_token(data)
Exemple #12
0
    def prepare(self, method, uri, headers, body):
        """Add OAuth parameters to the request.

        Parameters may be included from the body if the content-type is
        urlencoded, if no content type is set, a guess is made.
        """
        content_type = to_native(headers.get('Content-Type', ''))
        if self.signature_type == SIGNATURE_TYPE_BODY:
            content_type = CONTENT_TYPE_FORM_URLENCODED
        elif not content_type and extract_params(body):
            content_type = CONTENT_TYPE_FORM_URLENCODED

        if CONTENT_TYPE_FORM_URLENCODED in content_type:
            headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED
            uri, headers, body = self.sign(method, uri, headers, body)
        elif self.force_include_body:
            # To allow custom clients to work on non form encoded bodies.
            uri, headers, body = self.sign(method, uri, headers, body)
        else:
            # Omit body data in the signing of non form-encoded requests
            uri, headers, _ = self.sign(method, uri, headers, '')
            body = ''
        return uri, headers, body
Exemple #13
0
    def get_oauth_params(self, body, headers, nonce, timestamp):
        oauth_params = [
            ('oauth_nonce', nonce),
            ('oauth_timestamp', timestamp),
            ('oauth_version', '1.0'),
            ('oauth_signature_method', self.signature_method),
            ('oauth_consumer_key', self.client_id),
        ]
        if self.token:
            oauth_params.append(('oauth_token', self.token))
        if self.redirect_uri:
            oauth_params.append(('oauth_callback', self.redirect_uri))
        if self.verifier:
            oauth_params.append(('oauth_verifier', self.verifier))

        # https://tools.ietf.org/id/draft-eaton-oauth-bodyhash-00.html
        content_type = headers.get('Content-Type', '')
        not_form = not content_type.startswith(CONTENT_TYPE_FORM_URLENCODED)
        if body and content_type and not_form:
            sig = base64.b64encode(hashlib.sha1(to_bytes(body)).digest())
            oauth_params.append(('oauth_body_hash', to_native(sig)))

        return oauth_params
Exemple #14
0
def encode_client_secret_basic(client, method, uri, headers, body):
    text = '{}:{}'.format(client.client_id, client.client_secret)
    auth = to_native(base64.urlsafe_b64encode(to_bytes(text, 'latin1')))
    headers['Authorization'] = 'Basic {}'.format(auth)
    return uri, headers, body