mozilla / mozilla-django-oidc

A django OpenID Connect library
https://mozilla-django-oidc.readthedocs.io
Mozilla Public License 2.0
446 stars 166 forks source link

userinfo signature algorithms #376

Open matchaxnb opened 4 years ago

matchaxnb commented 4 years ago

Version: mozilla-django-oidc==1.2.4

Hello,

I have noticed the userinfo endpoint works only when the userinfo signature algorithm is set to "unsigned" (in Keycloak).

Indeed the code to get the userinfo after login is

    def get_userinfo(self, access_token, id_token, payload):
        """Return user details dictionary. The id_token and payload are not used in
        the default implementation, but may be used when overriding this method"""

        user_response = requests.get(
            self.OIDC_OP_USER_ENDPOINT,
            headers={
                'Authorization': 'Bearer {0}'.format(access_token),
                'Accept': 'application/json',
            },
            verify=self.get_settings('OIDC_VERIFY_SSL', True),
            timeout=self.get_settings('OIDC_TIMEOUT', None),
            proxies=self.get_settings('OIDC_PROXY', None))
        user_response.raise_for_status()
        return user_response.json()

There is no decoding step of the response and the library expects the response from the OIDC server to be unsigned unencrypted json while it may very well be a signed payload.

Would _verify_jws be a good starting point to support signed payloads from the userinfo endpoints?

strus38 commented 3 years ago

Hi

You saved my day ... I encounter this exact issue - and opened this defect: [https://github.com/mozilla/mozilla-django-oidc/issues/383] since the error message is quite not obvious!... so it will probably end up as a dupliacte of yours. With you change, it works better indeed. Thanks, I wish I saw it before!

rhclayto commented 2 years ago

@strus38

What change makes this work? I have the same problem.


Edit: My working code change below. (Works with Authelia OpenID provider.) In auth.py

import json
def get_userinfo(self, access_token, id_token, payload):
        """Return user details dictionary. The id_token and payload are not used in
        the default implementation, but may be used when overriding this method"""

        user_response = requests.get(
            self.OIDC_OP_USER_ENDPOINT,
            headers={
                'Authorization': 'Bearer {0}'.format(access_token)
            },
            verify=self.get_settings('OIDC_VERIFY_SSL', True),
            timeout=self.get_settings('OIDC_TIMEOUT', None),
            proxies=self.get_settings('OIDC_PROXY', None))
        user_response.raise_for_status()
        msg = user_response.text
        utf8 = msg.encode('utf-8')
        jws = JWS.from_compact(utf8)
        jwsjson = json.loads(jws.payload)
        return jwsjson
kirodh commented 3 months ago

@strus38

What change makes this work? I have the same problem.

Edit: My working code change below. (Works with Authelia OpenID provider.) In auth.py

import json
def get_userinfo(self, access_token, id_token, payload):
        """Return user details dictionary. The id_token and payload are not used in
        the default implementation, but may be used when overriding this method"""

        user_response = requests.get(
            self.OIDC_OP_USER_ENDPOINT,
            headers={
                'Authorization': 'Bearer {0}'.format(access_token)
            },
            verify=self.get_settings('OIDC_VERIFY_SSL', True),
            timeout=self.get_settings('OIDC_TIMEOUT', None),
            proxies=self.get_settings('OIDC_PROXY', None))
        user_response.raise_for_status()
        msg = user_response.text
        utf8 = msg.encode('utf-8')
        jws = JWS.from_compact(utf8)
        jwsjson = json.loads(jws.payload)
        return jwsjson

Can the developers please incorporate this into the code as it works. And its a pain to edit the code for docker setups.

In the mean time I have pulled the repo and are pulling it privately with the fix. Thank you for this package,its the only thing that works for me with the keycloak and django integration.

Thanks!