// 
// Decompiled by Procyon v0.6.0
// 

package com.nimbusds.jwt.proc;

import com.nimbusds.jose.JWEDecrypter;
import com.nimbusds.jose.proc.BadJWEException;
import com.nimbusds.jose.JWSVerifier;
import java.util.ListIterator;
import com.nimbusds.jose.proc.BadJWSException;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jwt.JWTParser;
import com.nimbusds.jose.KeySourceException;
import com.nimbusds.jose.proc.BadJOSEException;
import java.security.Key;
import java.util.List;
import com.nimbusds.jose.JWSHeader;
import java.text.ParseException;
import com.nimbusds.jwt.JWT;
import java.util.Set;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jose.crypto.factories.DefaultJWEDecrypterFactory;
import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory;
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
import com.nimbusds.jose.proc.JWEDecrypterFactory;
import com.nimbusds.jose.proc.JWSVerifierFactory;
import com.nimbusds.jose.proc.JWEKeySelector;
import com.nimbusds.jose.proc.JWSKeySelector;
import com.nimbusds.jose.proc.JOSEObjectTypeVerifier;
import com.nimbusds.jose.proc.SecurityContext;

public class DefaultJWTProcessor<C extends SecurityContext> implements ConfigurableJWTProcessor<C>
{
    private JOSEObjectTypeVerifier<C> jwsTypeVerifier;
    private JOSEObjectTypeVerifier<C> jweTypeVerifier;
    private JWSKeySelector<C> jwsKeySelector;
    private JWTClaimsSetAwareJWSKeySelector<C> claimsSetAwareJWSKeySelector;
    private JWEKeySelector<C> jweKeySelector;
    private JWSVerifierFactory jwsVerifierFactory;
    private JWEDecrypterFactory jweDecrypterFactory;
    private JWTClaimsSetVerifier<C> claimsVerifier;
    
    public DefaultJWTProcessor() {
        this.jwsTypeVerifier = DefaultJOSEObjectTypeVerifier.JWT;
        this.jweTypeVerifier = DefaultJOSEObjectTypeVerifier.JWT;
        this.jwsVerifierFactory = new DefaultJWSVerifierFactory();
        this.jweDecrypterFactory = new DefaultJWEDecrypterFactory();
        this.claimsVerifier = new DefaultJWTClaimsVerifier<C>(null, null);
    }
    
    @Override
    public JOSEObjectTypeVerifier<C> getJWSTypeVerifier() {
        return this.jwsTypeVerifier;
    }
    
    @Override
    public void setJWSTypeVerifier(final JOSEObjectTypeVerifier<C> jwsTypeVerifier) {
        this.jwsTypeVerifier = jwsTypeVerifier;
    }
    
    @Override
    public JWSKeySelector<C> getJWSKeySelector() {
        return this.jwsKeySelector;
    }
    
    @Override
    public void setJWSKeySelector(final JWSKeySelector<C> jwsKeySelector) {
        this.jwsKeySelector = jwsKeySelector;
    }
    
    @Override
    public JWTClaimsSetAwareJWSKeySelector<C> getJWTClaimsSetAwareJWSKeySelector() {
        return this.claimsSetAwareJWSKeySelector;
    }
    
    @Override
    public void setJWTClaimsSetAwareJWSKeySelector(final JWTClaimsSetAwareJWSKeySelector<C> jwsKeySelector) {
        this.claimsSetAwareJWSKeySelector = jwsKeySelector;
    }
    
    @Override
    public JOSEObjectTypeVerifier<C> getJWETypeVerifier() {
        return this.jweTypeVerifier;
    }
    
    @Override
    public void setJWETypeVerifier(final JOSEObjectTypeVerifier<C> jweTypeVerifier) {
        this.jweTypeVerifier = jweTypeVerifier;
    }
    
    @Override
    public JWEKeySelector<C> getJWEKeySelector() {
        return this.jweKeySelector;
    }
    
    @Override
    public void setJWEKeySelector(final JWEKeySelector<C> jweKeySelector) {
        this.jweKeySelector = jweKeySelector;
    }
    
    @Override
    public JWSVerifierFactory getJWSVerifierFactory() {
        return this.jwsVerifierFactory;
    }
    
    @Override
    public void setJWSVerifierFactory(final JWSVerifierFactory factory) {
        this.jwsVerifierFactory = factory;
    }
    
    @Override
    public JWEDecrypterFactory getJWEDecrypterFactory() {
        return this.jweDecrypterFactory;
    }
    
    @Override
    public void setJWEDecrypterFactory(final JWEDecrypterFactory factory) {
        this.jweDecrypterFactory = factory;
    }
    
    @Override
    public JWTClaimsSetVerifier<C> getJWTClaimsSetVerifier() {
        return this.claimsVerifier;
    }
    
    @Override
    public void setJWTClaimsSetVerifier(final JWTClaimsSetVerifier<C> claimsVerifier) {
        this.claimsVerifier = claimsVerifier;
    }
    
    protected JWTClaimsSet extractJWTClaimsSet(final JWT jwt) throws BadJWTException {
        try {
            return jwt.getJWTClaimsSet();
        }
        catch (final ParseException e) {
            throw new BadJWTException(e.getMessage(), e);
        }
    }
    
    protected JWTClaimsSet verifyJWTClaimsSet(final JWTClaimsSet claimsSet, final C context) throws BadJWTException {
        if (this.getJWTClaimsSetVerifier() != null) {
            this.getJWTClaimsSetVerifier().verify(claimsSet, context);
        }
        return claimsSet;
    }
    
    protected List<? extends Key> selectKeys(final JWSHeader header, final JWTClaimsSet claimsSet, final C context) throws KeySourceException, BadJOSEException {
        if (this.getJWTClaimsSetAwareJWSKeySelector() != null) {
            return this.getJWTClaimsSetAwareJWSKeySelector().selectKeys(header, claimsSet, context);
        }
        if (this.getJWSKeySelector() != null) {
            return this.getJWSKeySelector().selectJWSKeys(header, context);
        }
        throw new BadJOSEException("Signed JWT rejected: No JWS key selector is configured");
    }
    
    @Override
    public JWTClaimsSet process(final String jwtString, final C context) throws ParseException, BadJOSEException, JOSEException {
        return this.process(JWTParser.parse(jwtString), context);
    }
    
    @Override
    public JWTClaimsSet process(final JWT jwt, final C context) throws BadJOSEException, JOSEException {
        if (jwt instanceof SignedJWT) {
            return this.process((SignedJWT)jwt, context);
        }
        if (jwt instanceof EncryptedJWT) {
            return this.process((EncryptedJWT)jwt, context);
        }
        if (jwt instanceof PlainJWT) {
            return this.process((PlainJWT)jwt, context);
        }
        throw new JOSEException("Unexpected JWT object type: " + jwt.getClass());
    }
    
    @Override
    public JWTClaimsSet process(final PlainJWT plainJWT, final C context) throws BadJOSEException, JOSEException {
        if (this.jwsTypeVerifier == null) {
            throw new BadJOSEException("Plain JWT rejected: No JWS header typ (type) verifier is configured");
        }
        this.jwsTypeVerifier.verify(plainJWT.getHeader().getType(), context);
        throw new BadJOSEException("Unsecured (plain) JWTs are rejected, extend class to handle");
    }
    
    @Override
    public JWTClaimsSet process(final SignedJWT signedJWT, final C context) throws BadJOSEException, JOSEException {
        if (this.jwsTypeVerifier == null) {
            throw new BadJOSEException("Signed JWT rejected: No JWS header typ (type) verifier is configured");
        }
        this.jwsTypeVerifier.verify(signedJWT.getHeader().getType(), context);
        if (this.getJWSKeySelector() == null && this.getJWTClaimsSetAwareJWSKeySelector() == null) {
            throw new BadJOSEException("Signed JWT rejected: No JWS key selector is configured");
        }
        if (this.getJWSVerifierFactory() == null) {
            throw new JOSEException("No JWS verifier is configured");
        }
        final JWTClaimsSet claimsSet = this.extractJWTClaimsSet(signedJWT);
        final List<? extends Key> keyCandidates = this.selectKeys(signedJWT.getHeader(), claimsSet, context);
        if (keyCandidates == null || keyCandidates.isEmpty()) {
            throw new BadJOSEException("Signed JWT rejected: Another algorithm expected, or no matching key(s) found");
        }
        final ListIterator<? extends Key> it = keyCandidates.listIterator();
        while (it.hasNext()) {
            final JWSVerifier verifier = this.getJWSVerifierFactory().createJWSVerifier(signedJWT.getHeader(), (Key)it.next());
            if (verifier == null) {
                continue;
            }
            final boolean validSignature = signedJWT.verify(verifier);
            if (validSignature) {
                return this.verifyJWTClaimsSet(claimsSet, context);
            }
            if (!it.hasNext()) {
                throw new BadJWSException("Signed JWT rejected: Invalid signature");
            }
        }
        throw new BadJOSEException("JWS object rejected: No matching verifier(s) found");
    }
    
    @Override
    public JWTClaimsSet process(final EncryptedJWT encryptedJWT, final C context) throws BadJOSEException, JOSEException {
        if (this.jweTypeVerifier == null) {
            throw new BadJOSEException("Encrypted JWT rejected: No JWE header typ (type) verifier is configured");
        }
        this.jweTypeVerifier.verify(encryptedJWT.getHeader().getType(), context);
        if (this.getJWEKeySelector() == null) {
            throw new BadJOSEException("Encrypted JWT rejected: No JWE key selector is configured");
        }
        if (this.getJWEDecrypterFactory() == null) {
            throw new JOSEException("No JWE decrypter is configured");
        }
        final List<? extends Key> keyCandidates = this.getJWEKeySelector().selectJWEKeys(encryptedJWT.getHeader(), context);
        if (keyCandidates == null || keyCandidates.isEmpty()) {
            throw new BadJOSEException("Encrypted JWT rejected: Another algorithm expected, or no matching key(s) found");
        }
        final ListIterator<? extends Key> it = keyCandidates.listIterator();
        while (it.hasNext()) {
            final JWEDecrypter decrypter = this.getJWEDecrypterFactory().createJWEDecrypter(encryptedJWT.getHeader(), (Key)it.next());
            if (decrypter == null) {
                continue;
            }
            try {
                encryptedJWT.decrypt(decrypter);
            }
            catch (final JOSEException e) {
                if (it.hasNext()) {
                    continue;
                }
                throw new BadJWEException("Encrypted JWT rejected: " + e.getMessage(), e);
            }
            if (!"JWT".equalsIgnoreCase(encryptedJWT.getHeader().getContentType())) {
                final JWTClaimsSet claimsSet = this.extractJWTClaimsSet(encryptedJWT);
                return this.verifyJWTClaimsSet(claimsSet, context);
            }
            final SignedJWT signedJWTPayload = encryptedJWT.getPayload().toSignedJWT();
            if (signedJWTPayload == null) {
                throw new BadJWTException("The payload is not a nested signed JWT");
            }
            return this.process(signedJWTPayload, context);
        }
        throw new BadJOSEException("Encrypted JWT rejected: No matching decrypter(s) found");
    }
}
