Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: idpy oidcop frontend #378

Closed
wants to merge 34 commits into from

Conversation

peppelinux
Copy link
Member

@peppelinux peppelinux commented Aug 23, 2021

oidcop Satosa Frontend

satosa_oidcop

endpoints

  • provider discovery
  • jwks uri
  • authorization
  • token
  • userinfo
  • registration
  • registration_read endpoint
  • introspection endpoint (473310f)
  • token exchange

todo

  • unit tests
  • pytest mongo mock
  • test response_type = "code id_token token" (a61dc99)
  • auto prune expired sessions with mongodb index (137993f, mongo index)
  • token refresh (59c0a53)
  • rfc7523 - private_key_jwt test > a RP cannot reach the token endpoint if a user have not passed by authz endpoint before. private_key_jwt is a kind of authentication where the user interaction is not needed.
  • DPoP support
  • general frontend configuration yml file review and refactor (b7668f7)
  • satosa best practice compliances
  • Refactor scopes/claims configuration following this

self.config["INTERNAL_ATTRIBUTES"]["user_id_from_attrs"]
]
internal_response.subject_id = "".join(subject_id)
except KeyError as err:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise if a misconfiguration would happen SATOSA returns a KeyError exception from which it is difficult to know the cause from the logs.

This littl change makes satosa just more eloquent

@peppelinux
Copy link
Member Author

peppelinux commented Aug 24, 2021

Here a brief description about the main characteristics of this implementation.

Design principle 1

Anyone can migrate its oidcop configuration, from flask_op or django-oidc-op or whatever, in SATOSA and without any particular efforts. Looking at the example configuration we see that config.op.server_info have a standard SATOSA configuration with the only addition of the following customizations, needed in SATOSA for interoperational needs. These are:

  • autentication
        authentication:
          user:
            acr: urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocolPassword
            class: satosa.frontends.oidcop.user_authn.SatosaAuthnMethod
  • userinfo
       userinfo:
         class: satosa.frontends.oidcop.user_info.SatosaOidcUserInfo

authentication inherits oidcop.user_authn.user.UserAuthnMethod and overloads two methods involved in user authentication and verification. These tasks are handled by SATOSA in its authentication backends.

userinfo inherits oidcop.user_info.UserInfo and proposes a way to store the claims of the users when they comes from the backend. The claims are stored in the session database (actually mongodb) and then they will be fetched during userinfo endpoint (and also token endpoint, for having them optionally in id_token claims).

Weakness of SatosaOidcUserInfo

  1. It stores the claims of the user in the db
  2. It loads some temporary data and flush them before returning the userinfo response, here

unhandled features

  • oidcop SSO and cookies were not have been implemented because SATOSA doesn't support logout, because of this they are quite useless at this moment.
  • dynamic client registration and registration_api are not needed in my deployments but we can have them in a future roadmap (implemented)
  • DPoP, introspection and exchage SHOULD be implemented

Client and Session Storage

MongoDB is the storage, here some brief descriptions for a demo setup. The interface to SATOSA oidcop storage is satosa.frontends.oidcop.storage.base.SatosaOidcStorage and it have three methods:

  • get_client_by_id(self, client_id:str, expired:bool = True)
  • store_session_to_db(self, session_manager, **kwargs)
  • load_session_from_db(self, req_args, http_headers, session_manager, **kwargs)

satosa.frontends.oidcop.storage.mongo.Mongodb overloads them to have I/O operations on mongodb.

@peppelinux
Copy link
Member Author

peppelinux commented Aug 24, 2021

Storage design principles

At this time the storage logic is based on oidcop session_manager load/dump/flush methods.
Each time a request is handled by an endpoint the oidcop session manager loads the definition from the storage, only which one are strictly related to the request will be loaded in the in memory storage of oidcop.

Due to this fact, this implementation MUST be improved to properly detect the request to handle the introspection/exchange/registration endpoints.

Weakness of the storage model

it's transactional because it loads data from mongo to oidcop's in_memory engine before handling a request and dump the session data to mongo before flushing the inmem storage and doing the response. Each workers does its own.

Workers can't grows data in concurrency between many concurrent requests, by design.
Each workers loads and updates the data of a specific session by their own.

This approach CAN'T be deployed in a asyncio-based approach, but can't see any weakness with standalone workers.

Use case

In the case we have 2 threads that have 2 different client sessions for the same key (user_id;;client_id). The doubt is that in this draft implementation one of them will write its changes to the db first and the other will overwrite it.

Differently, in this implementation we have this behaviour:

The same client, with different browser/device, produce different sessions. We do not have a relation to any other_user_id;;client_id_ because the dumped session has all in it, another session will not touch the previous one, because:

  1. sessions are always flushed before and after operations
  2. sessions are always dumped entirely in a separate instance

This implementation definitely:

  • removed any relational constraints between many sessions produced by the same client;;user (oidcop subordinates)
  • prevents that a newly created Grant could add a subordinate to any other session and vice versa

To get instead relations between many sessions there will be the need to query the storage engine, with its native query lookup method.

@peppelinux peppelinux marked this pull request as ready for review August 29, 2021 20:06
@peppelinux peppelinux force-pushed the oidcop_front branch 2 times, most recently from 31dbb43 to 5e45050 Compare October 5, 2021 08:57
@peppelinux
Copy link
Member Author

@c00kiemon5ter
Copy link
Member

Added to the docs under external contributions: https://github.com/IdentityPython/SATOSA/blob/master/doc/README.md#external-contributions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants