""" Ping Auth OpenID Connect backend """ from jose import jwk, jwt from jose.jwt import ExpiredSignatureError, JWTClaimsError, JWTError from jose.utils import base64url_decode from social_core.backends.open_id_connect import OpenIdConnectAuth from social_core.exceptions import AuthTokenError class PingOpenIdConnect(OpenIdConnectAuth): name = "ping" # OIDC_ENDPOINT has the form 'https://auth.pingone.com//as' OIDC_ENDPOINT = "" REDIRECT_STATE = False ACCESS_TOKEN_METHOD = "POST" RESPONSE_TYPE = "code" USERNAME_KEY = "preferred_username" def find_valid_key(self, id_token): for key in self.get_jwks_keys(): rsakey = jwk.construct(key, algorithm="RS256") message, encoded_sig = id_token.rsplit(".", 1) decoded_sig = base64url_decode(encoded_sig.encode("utf-8")) if rsakey.verify(message.encode("utf-8"), decoded_sig): return key def validate_and_return_id_token(self, id_token, access_token): """ Validates the id_token according to the steps at http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation. """ client_id, client_secret = self.get_key_and_secret() key = self.find_valid_key(id_token) if not key: raise AuthTokenError(self, "Signature verification failed") rsakey = jwk.construct(key, algorithm="RS256") try: claims = jwt.decode( id_token, rsakey.to_pem().decode("utf-8"), algorithms=self.JWT_ALGORITHMS, audience=client_id, issuer=self.id_token_issuer(), access_token=access_token, options=self.JWT_DECODE_OPTIONS, ) except ExpiredSignatureError: raise AuthTokenError(self, "Signature has expired") except JWTClaimsError as error: raise AuthTokenError(self, str(error)) except JWTError: raise AuthTokenError(self, "Invalid signature") self.validate_claims(claims) return claims def get_user_details(self, response): username_key = self.setting("USERNAME_KEY", default=self.USERNAME_KEY) fullname, first_name, last_name = self.get_user_names( first_name=response.get("given_name"), last_name=response.get("family_name") ) return { "username": response.get(username_key), "email": response.get("email"), "fullname": fullname, "first_name": first_name, "last_name": last_name, }