Skip to content

Commit

Permalink
Use stateless authorization db, add post as client authentication, fi…
Browse files Browse the repository at this point in the history
…x bug with non-serializable sub

Signed-off-by: Emiliano Suñé <emiliano.sune@gmail.com>
  • Loading branch information
esune committed Oct 11, 2023
1 parent 9f72056 commit 7ad167f
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 14 deletions.
10 changes: 8 additions & 2 deletions oidc-controller/api/clientConfigurations/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
from enum import Enum
from typing import Optional, List
from typing import List, Optional

from pydantic import BaseModel, Field

from .examples import ex_client_config
from ..core.config import settings
from .examples import ex_client_config


class TOKENENDPOINTAUTHMETHODS(str, Enum):
client_secret_basic = "client_secret_basic"
client_secret_post = "client_secret_post"

@classmethod
def list(cls):
return list(map(lambda c: c.value, cls))


class ClientConfigurationBase(BaseModel):
Expand Down
4 changes: 2 additions & 2 deletions oidc-controller/api/core/oidc/issue_token_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def get_claims(
"""subject_identifer not found in presentation values,
generating random subject_identifier"""
)
sub_id_value = uuid.uuid4()
sub_id_value = str(uuid.uuid4())
else:
sub_id_value = sub_id_claim.value

Expand All @@ -115,7 +115,7 @@ def get_claims(
result[key] = value.value

return result

# TODO: Determine if this is useful to keep, and remove it if it's not. It is currently unused.
# renames and calculates dict members appropriate to
# https://openid.net/specs/openid-connect-core-1_0.html#IDToken
Expand Down
13 changes: 11 additions & 2 deletions oidc-controller/api/core/oidc/provider.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os
import secrets
from urllib.parse import urlparse

import structlog
import structlog.typing
from api.clientConfigurations.models import TOKENENDPOINTAUTHMETHODS
from api.core.config import settings
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
Expand All @@ -11,6 +13,7 @@
from pymongo.database import Database
from pyop.authz_state import AuthorizationState
from pyop.provider import Provider
from pyop.storage import StatelessWrapper
from pyop.subject_identifier import HashBasedSubjectIdentifierFactory
from pyop.userinfo import Userinfo

Expand Down Expand Up @@ -105,14 +108,15 @@ def pem_file_exists(filepath) -> bool:
"request_parameter_supported": True,
"request_uri_parameter_supported": False,
"scopes_supported": ["openid"],
"token_endpoint_auth_methods_supported": ["client_secret_basic"],
"token_endpoint_auth_methods_supported": TOKENENDPOINTAUTHMETHODS.list(),
"frontchannel_logout_supported": True,
"frontchannel_logout_session_supported": True,
"backchannel_logout_supported": True,
"backchannel_logout_session_supported": True,
}

subject_id_factory = HashBasedSubjectIdentifierFactory(settings.SUBJECT_ID_HASH_SALT)
stateless_storage = StatelessWrapper("vc-authn", secrets.token_urlsafe())

# placeholder that gets set on app_start and write operations to ClientConfigurationCRUD
provider = None
Expand All @@ -131,7 +135,12 @@ async def init_provider(db: Database):
provider = Provider(
signing_key,
configuration_information,
AuthorizationState(subject_id_factory),
AuthorizationState(
subject_id_factory,
authorization_code_db=stateless_storage,
access_token_db=stateless_storage,
refresh_token_db=stateless_storage,
),
client_db,
Userinfo(user_db),
)
14 changes: 6 additions & 8 deletions oidc-controller/api/routers/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import qrcode
import structlog
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from fastapi import status as http_status
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from jinja2 import Template
from oic.oic.message import AccessTokenRequest, AuthorizationRequest
from pymongo.database import Database
Expand Down Expand Up @@ -88,9 +88,10 @@ async def get_authorize(request: Request, db: Database = Depends(get_db)):
)
except InvalidAuthenticationRequest as e:
raise HTTPException(
status_code=http_status.HTTP_400_BAD_REQUEST,
detail=f"Invalid auth request: {e}")

status_code=http_status.HTTP_400_BAD_REQUEST,
detail=f"Invalid auth request: {e}",
)

# fetch placeholder user/model and create proof
authn_response = provider.provider.authorize(model, "vc-user")

Expand Down Expand Up @@ -161,17 +162,14 @@ async def post_token(request: Request, db: Database = Depends(get_db)):
"""Called by oidc platform to retrieve token contents"""
form = await request.form()
model = AccessTokenRequest().from_dict(form._dict)
client = AcapyClient()

auth_session = await AuthSessionCRUD(db).get_by_pyop_auth_code(model.get("code"))
ver_config = await VerificationConfigCRUD(db).get(auth_session.ver_config_id)
claims = Token.get_claims(auth_session, ver_config)

# modify subject identifier value to use vc-attribute as configured
new_sub = claims.pop("sub")
provider.provider.authz_state.authorization_codes[model.get("code")][
"public"
] = new_sub
provider.provider.authz_state.subject_identifiers["vc-user"]["public"] = new_sub

# convert form data to what library expects, Flask.app.request.get_data()
data = urlencode(form._dict)
Expand Down

0 comments on commit 7ad167f

Please sign in to comment.