001/* 002* The contents of this file are subject to the terms of the Common Development and 003* Distribution License (the License). You may not use this file except in compliance with the 004* License. 005* 006* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007* specific language governing permission and limitations under the License. 008* 009* When distributing Covered Software, include this CDDL Header Notice in each file and include 010* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011* Header, with the fields enclosed by brackets [] replaced by your own identifying 012* information: "Portions copyright [year] [name of copyright owner]". 013* 014* Copyright 2014-2016 ForgeRock AS. 015*/ 016package org.forgerock.jaspi.modules.openid.resolvers; 017 018import java.security.Key; 019import java.security.interfaces.ECPublicKey; 020import java.security.interfaces.RSAPublicKey; 021import java.util.Date; 022import javax.crypto.SecretKey; 023 024import org.forgerock.jaspi.modules.openid.exceptions.InvalidIssException; 025import org.forgerock.jaspi.modules.openid.exceptions.JwtExpiredException; 026import org.forgerock.jaspi.modules.openid.exceptions.OpenIdConnectVerificationException; 027import org.forgerock.json.jose.jws.SignedJwt; 028import org.forgerock.json.jose.jws.SigningManager; 029import org.forgerock.json.jose.jws.handlers.SigningHandler; 030 031/** 032 * Implementation of the OpenIdResolver interface. Comments in the specific verify methods 033 * are taken directly from OpenID Connect Basic Client Implementer's Guide 1.0, 034 * section 2.2.1 - ID Token Validation 035 * 036 * Currently we do NO validation against the client ID/intended audience. 037 * 038 * @see <a href="http://openid.net/specs/openid-connect-basic-1_0.html"> 039 * http://openid.net/specs/openid-connect-basic-1_0.html</a> 040 */ 041public abstract class BaseOpenIdResolver implements OpenIdResolver { 042 043 private final String issuer; 044 045 /** 046 * Abstract constructor for setting the issuer's identity. 047 * 048 * @param issuer The issuer (provider) of the Open Id Connect id token 049 */ 050 public BaseOpenIdResolver(final String issuer) { 051 this.issuer = issuer; 052 } 053 054 /** 055 * Verifies the issuer is exactly who it is expected to be. 056 * 057 * @param issuerName The name of the claimed issuer 058 * @throws InvalidIssException if the expected issuer and actual issuer do not match 059 */ 060 void verifyIssuer(final String issuerName) throws InvalidIssException { 061 //The issuer MUST exactly match the value of the iss (issuer) Claim. 062 if (!issuer.equals(issuerName)) { 063 throw new InvalidIssException("Invalid issuer"); 064 } 065 } 066 067 /** 068 * Verifies that the current date is no later than the expiry date on the JWT. 069 * 070 * @param expirationTime time at which this id token expires 071 * @throws JwtExpiredException if the current time is after the expired time 072 */ 073 void verifyExpiration(final Date expirationTime) throws JwtExpiredException { 074 //Expiration time on or after which the ID Token MUST NOT be accepted for processing. 075 if (new Date().after(expirationTime)) { 076 throw new JwtExpiredException("Token expired"); 077 } 078 } 079 080 /** 081 * {@inheritDoc} 082 */ 083 @Override 084 public void validateIdentity(final SignedJwt idClaim) throws OpenIdConnectVerificationException { 085 086 if (idClaim == null) { 087 throw new OpenIdConnectVerificationException("A valid SignedJWT must be supplied to the resolver"); 088 } 089 090 verifyIssuer(idClaim.getClaimsSet().getIssuer()); 091 verifyExpiration(idClaim.getClaimsSet().getExpirationTime()); 092 } 093 094 /** 095 * Determine an appropriate signing handler to use for verifying signatures using the given verification key. 096 * 097 * @param signingManager the signing manager. 098 * @param key the verification key. 099 * @return the appropriate signing handler. 100 * @throws IllegalArgumentException if no handler can be determined for the given key. 101 */ 102 protected SigningHandler createSigningHandlerForKey(final SigningManager signingManager, final Key key) { 103 if (key instanceof ECPublicKey) { 104 return signingManager.newEcdsaVerificationHandler(((ECPublicKey) key)); 105 } else if (key instanceof RSAPublicKey) { 106 return signingManager.newRsaSigningHandler(key); 107 } else if (key instanceof SecretKey) { 108 return signingManager.newHmacSigningHandler(key.getEncoded()); 109 } else { 110 throw new IllegalArgumentException("Unable to determine signing algorithm"); 111 } 112 } 113 114 /** 115 * {@inheritDoc} 116 */ 117 @Override 118 public String getIssuer() { 119 return issuer; 120 } 121}