001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2020, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.openid.connect.sdk.federation.api; 019 020 021import net.jcip.annotations.Immutable; 022 023import com.nimbusds.common.contenttype.ContentType; 024import com.nimbusds.jose.JOSEException; 025import com.nimbusds.jose.JOSEObjectType; 026import com.nimbusds.jose.JWSAlgorithm; 027import com.nimbusds.jose.JWSObject; 028import com.nimbusds.jose.jwk.JWK; 029import com.nimbusds.jose.jwk.JWKSet; 030import com.nimbusds.jose.proc.BadJOSEException; 031import com.nimbusds.jose.util.Base64URL; 032import com.nimbusds.jwt.SignedJWT; 033import com.nimbusds.oauth2.sdk.ParseException; 034import com.nimbusds.openid.connect.sdk.federation.utils.JWTUtils; 035 036 037/** 038 * Resolve statement. 039 * 040 * <p>Related specifications: 041 * 042 * <ul> 043 * <li>OpenID Connect Federation 1.0, section 7.2.2. 044 * </ul> 045 */ 046@Immutable 047public final class ResolveStatement { 048 049 050 /** 051 * The resolve statement JOSE object type 052 * ({@code resolve-response+jwt}). 053 */ 054 public static final JOSEObjectType JOSE_OBJECT_TYPE = new JOSEObjectType("resolve-response+jwt"); 055 056 057 /** 058 * The resolve response content type 059 * ({@code application/resolve-response+jwt}). 060 */ 061 public static final ContentType CONTENT_TYPE = new ContentType("application", JOSE_OBJECT_TYPE.getType()); 062 063 064 /** 065 * The signed statement as signed JWT. 066 */ 067 private final SignedJWT statementJWT; 068 069 070 /** 071 * The statement claims. 072 */ 073 private final ResolveClaimsSet claimsSet; 074 075 076 /** 077 * Creates a new resolve statement. 078 * 079 * @param statementJWT The signed statement as signed JWT. Must not be 080 * {@code null}. 081 * @param claimsSet The statement claims. Must not be {@code null}. 082 */ 083 private ResolveStatement(final SignedJWT statementJWT, 084 final ResolveClaimsSet claimsSet) { 085 086 if (statementJWT == null) { 087 throw new IllegalArgumentException("The entity statement must not be null"); 088 } 089 if (JWSObject.State.UNSIGNED.equals(statementJWT.getState())) { 090 throw new IllegalArgumentException("The statement is not signed"); 091 } 092 this.statementJWT = statementJWT; 093 094 if (claimsSet == null) { 095 throw new IllegalArgumentException("The entity statement claims set must not be null"); 096 } 097 this.claimsSet = claimsSet; 098 } 099 100 101 /** 102 * Returns the signed statement. 103 * 104 * @return The signed statement as signed JWT. 105 */ 106 public SignedJWT getSignedStatement() { 107 return statementJWT; 108 } 109 110 111 /** 112 * Returns the statement claims. 113 * 114 * @return The statement claims. 115 */ 116 public ResolveClaimsSet getClaimsSet() { 117 return claimsSet; 118 } 119 120 121 /** 122 * Verifies the signature and checks the statement type, issue and 123 * expiration times. 124 * 125 * @param jwkSet The JWK set to use for the signature verification. 126 * Must not be {@code null}. 127 * 128 * @return The SHA-256 thumbprint of the key used to successfully 129 * verify the signature. 130 * 131 * @throws BadJOSEException If the signature is invalid or the 132 * statement is expired or before the issue 133 * time. 134 * @throws JOSEException On an internal JOSE exception. 135 */ 136 public Base64URL verifySignature(final JWKSet jwkSet) 137 throws BadJOSEException, JOSEException { 138 139 return JWTUtils.verifySignature( 140 statementJWT, 141 JOSE_OBJECT_TYPE, 142 new ResolveClaimsVerifier(), 143 jwkSet); 144 } 145 146 147 /** 148 * Signs the specified resolve claims set. 149 * 150 * @param claimsSet The claims set. Must not be {@code null}. 151 * @param signingJWK The private signing JWK. Must be contained in the 152 * entity JWK set and not {@code null}. 153 * 154 * @return The signed resolve statement. 155 * 156 * @throws JOSEException On a internal signing exception. 157 */ 158 public static ResolveStatement sign(final ResolveClaimsSet claimsSet, 159 final JWK signingJWK) 160 throws JOSEException { 161 162 return sign(claimsSet, signingJWK, JWTUtils.resolveSigningAlgorithm(signingJWK)); 163 } 164 165 166 /** 167 * Signs the specified resolve claims set. 168 * 169 * @param claimsSet The claims set. Must not be {@code null}. 170 * @param signingJWK The private signing JWK. Must be contained in the 171 * entity JWK set and not {@code null}. 172 * @param jwsAlg The signing algorithm. Must be supported by the 173 * JWK and not {@code null}. 174 * 175 * @return The signed resolve statement. 176 * 177 * @throws JOSEException On an internal signing exception. 178 */ 179 public static ResolveStatement sign(final ResolveClaimsSet claimsSet, 180 final JWK signingJWK, 181 final JWSAlgorithm jwsAlg) 182 throws JOSEException { 183 184 try { 185 return new ResolveStatement( 186 JWTUtils.sign( 187 signingJWK, 188 jwsAlg, 189 JOSE_OBJECT_TYPE, 190 claimsSet.toJWTClaimsSet()), 191 claimsSet); 192 } catch (ParseException e) { 193 throw new JOSEException(e.getMessage(), e); 194 } 195 } 196 197 198 /** 199 * Parses a resolve statement. 200 * 201 * @param signedStmt The signed statement as a signed JWT. Must not be 202 * {@code null}. 203 * 204 * @return The resolve statement. 205 * 206 * @throws ParseException If parsing failed. 207 */ 208 public static ResolveStatement parse(final SignedJWT signedStmt) 209 throws ParseException { 210 211 return new ResolveStatement(signedStmt, new ResolveClaimsSet(JWTUtils.parseSignedJWTClaimsSet(signedStmt))); 212 } 213 214 215 /** 216 * Parses a resolve statement. 217 * 218 * @param signedStmtString The signed statement as a signed JWT string. 219 * Must not be {@code null}. 220 * 221 * @return The resolve statement. 222 * 223 * @throws ParseException If parsing failed. 224 */ 225 public static ResolveStatement parse(final String signedStmtString) 226 throws ParseException { 227 228 try { 229 return parse(SignedJWT.parse(signedStmtString)); 230 } catch (java.text.ParseException e) { 231 throw new ParseException("Invalid resolve statement: " + e.getMessage(), e); 232 } 233 } 234}