inabajunmr / azidp4j

[alpha] Java OAuth 2.0 Authorization Server & OpenID Connect Identity Provider Library for any web application frameworks.
MIT License
4 stars 0 forks source link

claims handling #8

Open inabajunmr opened 2 years ago

inabajunmr commented 2 years ago

how does library handle claims and scope? how does user define mapping?

inabajunmr commented 1 year ago

proposal

package org.azidp4j.token.idtoken;

import com.nimbusds.jose.JOSEObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.PlainObject;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.util.Base64URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import org.azidp4j.AzIdPConfig;
import org.azidp4j.client.SigningAlgorithm;
import org.azidp4j.jwt.JWSIssuer;
import org.azidp4j.util.MapUtil;

public class IDTokenIssuer {

    private final AzIdPConfig config;

    private final JWSIssuer jwsIssuer;

    private final Function<SigningAlgorithm, String> kidSupplier;

    private final ClaimsAssembler claimsAssembler; // TODO

    public IDTokenIssuer(
            AzIdPConfig config, JWKSet jwkSet, Function<SigningAlgorithm, String> kidSupplier) {
        this.config = config;
        this.jwsIssuer = new JWSIssuer(jwkSet);
        this.kidSupplier = kidSupplier;
    }

    public JOSEObject issue(
            String sub,
            String clientId,
            Long authTime,
            String nonce,
            String accessToken,
            String authorizationCode,
            SigningAlgorithm alg) {
        var jti = UUID.randomUUID().toString();
        var atHash = accessToken != null ? calculateXHash(accessToken) : null;
        var cHash = authorizationCode != null ? calculateXHash(authorizationCode) : null;
        var profileClaims = claimsAssembler.assemble(sub, scope); // TODO
        Map<String, Object> claims =
                MapUtil.nullRemovedMap(
                        "iss",
                        config.issuer,
                        "sub",
                        sub,
                        "aud",
                        clientId,
                        "exp",
                        Instant.now().getEpochSecond() + config.idTokenExpiration.toSeconds(),
                        "iat",
                        Instant.now().getEpochSecond(),
                        "jti",
                        jti,
                        "auth_time",
                        authTime,
                        "nonce",
                        nonce,
                        "azp",
                        clientId,
                        "at_hash",
                        atHash,
                        "c_hash",
                        cHash);
        var merged = merge(claims, profileClaims); // TODO
        if (alg.equals(SigningAlgorithm.none)) {
            return new PlainObject(new Payload(merged)); // TODO
        }
        return jwsIssuer.issue(kidSupplier.apply(alg), null, merged); // TODO
    }

    private String calculateXHash(String token) {
        try {
            var sha256 = MessageDigest.getInstance("SHA-256");
            var hash = sha256.digest(token.getBytes());
            return Base64URL.encode(Arrays.copyOfRange(hash, 0, hash.length / 2)).toString();
        } catch (NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
    }
}