001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, 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.op; 019 020 021import java.util.ArrayList; 022import java.util.LinkedList; 023import java.util.List; 024 025import net.jcip.annotations.Immutable; 026 027import com.nimbusds.oauth2.sdk.AuthorizationRequest; 028import com.nimbusds.oauth2.sdk.GeneralException; 029import com.nimbusds.oauth2.sdk.OAuth2Error; 030import com.nimbusds.oauth2.sdk.ciba.CIBARequest; 031import com.nimbusds.openid.connect.sdk.AuthenticationRequest; 032import com.nimbusds.openid.connect.sdk.OIDCClaimsRequest; 033import com.nimbusds.openid.connect.sdk.OIDCScopeValue; 034import com.nimbusds.openid.connect.sdk.claims.ACR; 035import com.nimbusds.openid.connect.sdk.claims.ClaimRequirement; 036import com.nimbusds.openid.connect.sdk.claims.ClaimsSetRequest; 037import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation; 038 039 040/** 041 * Resolved authentication Context Class Reference (ACR) request. 042 */ 043@Immutable 044public final class ACRRequest { 045 046 047 /** 048 * The essential ACR values. 049 */ 050 private final List<ACR> essentialACRs; 051 052 053 /** 054 * The voluntary ACR values. 055 */ 056 private final List<ACR> voluntaryACRs; 057 058 059 /** 060 * Creates a new Authentication Context Class Reference (ACR) request. 061 * 062 * @param essentialACRs The requested essential ACR values, by order of 063 * preference, {@code null} if not specified. 064 * @param voluntaryACRs The requested voluntary ACR values, by order of 065 * preference, {@code null} if not specified. 066 */ 067 public ACRRequest(final List<ACR> essentialACRs, final List<ACR> voluntaryACRs) { 068 069 this.essentialACRs = essentialACRs; 070 this.voluntaryACRs = voluntaryACRs; 071 } 072 073 074 /** 075 * Gets the requested essential ACR values. 076 * 077 * @return The essential ACR values, by order of preference, 078 * {@code null} if not specified. 079 */ 080 public List<ACR> getEssentialACRs() { 081 082 return essentialACRs; 083 } 084 085 086 /** 087 * Gets the requested voluntary ACR values. 088 * 089 * @return The voluntary ACR values, by order of preference, 090 * {@code null} if not specified. 091 */ 092 public List<ACR> getVoluntaryACRs() { 093 094 return voluntaryACRs; 095 } 096 097 098 /** 099 * Checks if this ACR request has no essential or voluntary values 100 * specified. 101 * 102 * @return {@code true} if this ACR request doesn't specify any 103 * essential or voluntary values, else {@code false}. 104 */ 105 public boolean isEmpty() { 106 107 return !(essentialACRs != null && !essentialACRs.isEmpty()) && 108 !(voluntaryACRs != null && !voluntaryACRs.isEmpty()); 109 } 110 111 112 /** 113 * Applies the registered default ACR values for the requesting client 114 * (as a voluntary ACR value, provided no ACR values were explicitly 115 * requested). 116 * 117 * @param clientInfo The registered client information. Must not be 118 * {@code null}. 119 * 120 * @return The ACR request, updated if registered default ACR values 121 * were applied. 122 */ 123 public ACRRequest applyDefaultACRs(final OIDCClientInformation clientInfo) { 124 125 // Apply default ACR from client reg store as voluntary? 126 if (isEmpty()) { 127 if (clientInfo.getOIDCMetadata().getDefaultACRs() != null) { 128 List<ACR> voluntaryACRs = new LinkedList<>(clientInfo.getOIDCMetadata().getDefaultACRs()); 129 return new ACRRequest(null, voluntaryACRs); 130 } 131 } 132 133 return this; 134 } 135 136 137 /** 138 * Ensures all requested essential ACR values are supported by those 139 * supported by the OpenID provider. 140 * 141 * @param authzRequest The OAuth 2.0 authorisation request / OpenID 142 * authentication request. Must not be 143 * {@code null}. 144 * @param supportedACRs The ACR values supported by the OpenID 145 * provider, {@code null} if not specified. 146 * 147 * @throws GeneralException If a requested essential ACR value is not 148 * supported by the OpenID provider. 149 */ 150 public void ensureACRSupport(final AuthorizationRequest authzRequest, final List<ACR> supportedACRs) 151 throws GeneralException { 152 153 // Ensure any requested essential ACR is supported 154 if (getEssentialACRs() != null) { 155 156 boolean foundSupportedEssentialACR = false; 157 158 for (ACR acr: getEssentialACRs()) { 159 160 if (supportedACRs != null && supportedACRs.contains(acr)) { 161 foundSupportedEssentialACR = true; 162 break; 163 } 164 } 165 166 if (! foundSupportedEssentialACR) { 167 String msg = "Requested essential ACR(s) not supported"; 168 throw new GeneralException(msg, 169 OAuth2Error.ACCESS_DENIED.appendDescription(": " + msg), 170 authzRequest.getClientID(), 171 authzRequest.getRedirectionURI(), 172 authzRequest.impliedResponseMode(), 173 authzRequest.getState()); 174 } 175 } 176 } 177 178 179 /** 180 * Ensures all requested essential ACR values are supported by the 181 * OpenID provider. 182 * 183 * @param authRequest The OpenID authentication request. Must not be 184 * {@code null}. 185 * @param opMetadata The OpenID provider metadata. Must not be 186 * {@code null}. 187 * 188 * @throws GeneralException If a requested essential ACR value is not 189 * supported by the OpenID provider. 190 */ 191 @Deprecated 192 public void ensureACRSupport(final AuthenticationRequest authRequest, final OIDCProviderMetadata opMetadata) 193 throws GeneralException { 194 195 ensureACRSupport(authRequest, opMetadata.getACRs()); 196 } 197 198 199 /** 200 * Resolves the requested essential and voluntary ACR values from the 201 * specified OAuth 2.0 authorisation request / OpenID authentication 202 * request. 203 * 204 * @param authzRequest The OAuth 2.0 authorisation request / OpenID 205 * authentication request. Should be resolved. Must 206 * not be {@code null}. 207 * 208 * @return The resolved ACR request. 209 */ 210 public static ACRRequest resolve(final AuthorizationRequest authzRequest) { 211 212 if (! (authzRequest instanceof AuthenticationRequest)) { 213 // Plain OAuth 2.0 214 return new ACRRequest(null, null); 215 } 216 217 // OpenID 218 AuthenticationRequest authRequest = (AuthenticationRequest) authzRequest; 219 220 // OpenID 221 return resolve(authRequest.getACRValues(), authRequest.getOIDCClaims()); 222 } 223 224 225 /** 226 * Resolves the requested essential and voluntary ACR values from the 227 * specified CIBA request. 228 * 229 * @param cibaRequest The CIBA request. Must be resolved and not 230 * {@code null}. 231 * 232 * @return The resolved ACR request. 233 */ 234 public static ACRRequest resolve(final CIBARequest cibaRequest) { 235 236 if (cibaRequest.isSigned()) { 237 throw new IllegalArgumentException("The CIBA request must be resolved (not signed)"); 238 } 239 240 if (cibaRequest.getScope() != null && ! cibaRequest.getScope().contains(OIDCScopeValue.OPENID)) { 241 // Plain OAuth 2.0 242 return new ACRRequest(null, null); 243 } 244 245 // OpenID 246 return resolve(cibaRequest.getACRValues(), cibaRequest.getOIDCClaims()); 247 } 248 249 250 251 private static ClaimsSetRequest.Entry getACRClaimRequest(final OIDCClaimsRequest claimsRequest) { 252 253 if (claimsRequest == null) { 254 return null; 255 } 256 257 ClaimsSetRequest idTokenClaimsRequest = claimsRequest.getIDTokenClaimsRequest(); 258 259 if (idTokenClaimsRequest == null) { 260 return null; 261 } 262 263 for (ClaimsSetRequest.Entry en: idTokenClaimsRequest.getEntries()) { 264 if ("acr".equals(en.getClaimName())) { 265 return en; 266 } 267 } 268 return null; 269 } 270 271 272 /** 273 * Resolves the requested essential and voluntary ACR values from the 274 * specified top-level {@code acr_values} request parameter and 275 * {@code claims} request parameter. 276 * 277 * @param acrValues The top-level {@code acr_values} request 278 * parameter, {@code null} if not specified. 279 * @param claimsRequest The OpenID {@code claims} request parameter, 280 * {@code null} if not specified. 281 * 282 * @return The resolved ACR request. 283 */ 284 public static ACRRequest resolve(final List<ACR> acrValues, final OIDCClaimsRequest claimsRequest) { 285 286 List<ACR> essentialACRs = null; 287 List<ACR> voluntaryACRs = null; 288 289 ClaimsSetRequest.Entry en = getACRClaimRequest(claimsRequest); 290 291 if (en != null) { 292 if (en.getClaimRequirement().equals(ClaimRequirement.ESSENTIAL)) { 293 294 essentialACRs = new ArrayList<>(); 295 296 if (en.getValueAsString() != null) 297 essentialACRs.add(new ACR(en.getValueAsString())); 298 299 if (en.getValuesAsListOfStrings() != null) { 300 for (String v: en.getValuesAsListOfStrings()) 301 essentialACRs.add(new ACR(v)); 302 } 303 } else { 304 voluntaryACRs = new ArrayList<>(); 305 306 if (en.getValueAsString() != null) 307 voluntaryACRs.add(new ACR(en.getValueAsString())); 308 309 if (en.getValuesAsListOfStrings() != null) { 310 311 for (String v: en.getValuesAsListOfStrings()) 312 voluntaryACRs.add(new ACR(v)); 313 } 314 } 315 } 316 317 if (acrValues != null) { 318 319 if (voluntaryACRs == null) 320 voluntaryACRs = new ArrayList<>(); 321 322 voluntaryACRs.addAll(acrValues); 323 } 324 325 return new ACRRequest(essentialACRs, voluntaryACRs); 326 } 327}