def test_default_scope2claims():
    assert scope2claims(["openid"]) == {"sub": None}
    assert set(scope2claims(["profile"]).keys()) == {
        "name",
        "given_name",
        "family_name",
        "middle_name",
        "nickname",
        "profile",
        "picture",
        "website",
        "gender",
        "birthdate",
        "zoneinfo",
        "locale",
        "updated_at",
        "preferred_username",
    }
    assert set(scope2claims(["email"]).keys()) == {"email", "email_verified"}
    assert set(scope2claims(["address"]).keys()) == {"address"}
    assert set(scope2claims(["phone"]).keys()) == {
        "phone_number",
        "phone_number_verified",
    }
    assert scope2claims(["offline_access"]) == {}

    assert scope2claims(["openid", "email", "phone"]) == {
        "sub": None,
        "email": None,
        "email_verified": None,
        "phone_number": None,
        "phone_number_verified": None,
    }
def test_custom_scopes():
    custom_scopes = {
        "research_and_scholarship": [
            "name",
            "given_name",
            "family_name",
            "email",
            "email_verified",
            "sub",
            "iss",
            "eduperson_scoped_affiliation",
        ]
    }

    _scopes = SCOPE2CLAIMS.copy()
    _scopes.update(custom_scopes)

    assert set(scope2claims(["email"], map=_scopes).keys()) == {
        "email",
        "email_verified",
    }
    assert set(scope2claims(["address"], map=_scopes).keys()) == {"address"}
    assert set(scope2claims(["phone"], map=_scopes).keys()) == {
        "phone_number",
        "phone_number_verified",
    }

    assert set(scope2claims(["research_and_scholarship"],
                            map=_scopes).keys()) == {
                                "name",
                                "given_name",
                                "family_name",
                                "email",
                                "email_verified",
                                "sub",
                                "iss",
                                "eduperson_scoped_affiliation",
                            }
Example #3
0
    def __call__(self, sid: str, uinfo: Dict, sinfo: Dict, *args,
                 aud: Optional[Any], client_id: Optional[str], **kwargs):
        """
        Return a token.

        :param sid: Session id
        :param uinfo: User information
        :param sinfo: Session information
        :param aud: The default audience == client_id
        :return:
        """
        payload = {"sid": sid, "ttype": self.type, "sub": sinfo["sub"]}

        if self.add_claims:
            self.do_add_claims(payload, uinfo, self.add_claims)
        if self.add_claims_by_scope:
            self.do_add_claims(
                payload,
                uinfo,
                scope2claims(sinfo["authn_req"]["scope"],
                             map=self.scope_claims_map).keys(),
            )
        # Add claims if is access token
        if self.type == 'T' and self.enable_claims_per_client:
            client = self.cdb.get(client_id, {})
            client_claims = client.get("access_token_claims")
            if client_claims:
                self.do_add_claims(payload, uinfo, client_claims)

        payload.update(kwargs)
        signer = JWT(
            key_jar=self.key_jar,
            iss=self.issuer,
            lifetime=self.lifetime,
            sign_alg=self.alg,
        )

        if aud is None:
            _aud = self.def_aud
        else:
            _aud = aud if isinstance(aud, list) else [aud]
            _aud.extend(self.def_aud)

        return signer.pack(payload, aud=_aud)
Example #4
0
    def __call__(self, sid: str, uinfo: Dict, sinfo: Dict, *args,
                 aud: Optional[Any], **kwargs):
        """
        Return a token.

        :param sid: Session id
        :param uinfo: User information
        :param sinfo: Session information
        :param aud: The default audience == client_id
        :return:
        """
        payload = {"sid": sid, "ttype": self.type, "sub": sinfo["sub"]}

        if "add_claims" in self.args:
            self.add_claims(payload, uinfo, self.args["add_claims"])
        if self.args.get("add_claims_by_scope", False):
            self.add_claims(
                payload,
                uinfo,
                scope2claims(sinfo["authn_req"]["scope"],
                             map=self.scope_claims_map).keys(),
            )

        payload.update(kwargs)
        signer = JWT(
            key_jar=self.key_jar,
            iss=self.issuer,
            lifetime=self.lifetime,
            sign_alg=self.alg,
        )

        if aud is None:
            _aud = self.def_aud
        else:
            _aud = aud if isinstance(aud, list) else [aud]
            _aud.extend(self.def_aud)

        return signer.pack(payload, aud=_aud)
Example #5
0
def collect_user_info(endpoint_context,
                      session,
                      userinfo_claims=None,
                      scope_to_claims=None):
    """
    Collect information about a user.
    This can happen in two cases, either when constructing an IdToken or
    when returning user info through the UserInfo endpoint

    :param session: Session information
    :param userinfo_claims: user info claims
    :return: User info
    """
    authn_req = session["authn_req"]
    if scope_to_claims is None:
        scope_to_claims = endpoint_context.scope2claims

    supported_scopes = [
        s for s in authn_req["scope"]
        if s in endpoint_context.provider_info["scopes_supported"]
    ]

    if userinfo_claims is None:
        uic = scope2claims(supported_scopes, map=scope_to_claims)

        # Get only keys allowed by user and update the dict if such info
        # is stored in session
        perm_set = session.get("permission")
        if perm_set:
            uic = {key: uic[key] for key in uic if key in perm_set}

        uic = update_claims(session,
                            "userinfo",
                            provider_info=endpoint_context.provider_info,
                            old_claims=uic)

        if uic:
            userinfo_claims = Claims(**uic)
        else:
            userinfo_claims = None

        logger.debug("userinfo_claim: %s" %
                     sanitize(userinfo_claims.to_dict()))

    logger.debug("Session info: %s" % sanitize(session))

    authn_event = session["authn_event"]
    if authn_event:
        uid = authn_event["uid"]
    else:
        uid = session["uid"]

    info = endpoint_context.userinfo(uid, authn_req["client_id"],
                                     userinfo_claims)

    if "sub" in userinfo_claims:
        if not claims_match(session["sub"], userinfo_claims["sub"]):
            raise FailedAuthentication("Unmatched sub claim")

    info["sub"] = session["sub"]
    try:
        logger.debug("user_info_response: {}".format(info))
    except UnicodeEncodeError:
        logger.debug("user_info_response: {}".format(info.encode("utf-8")))

    return info