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 com.nimbusds.oauth2.sdk.AuthorizationRequest; 026import com.nimbusds.oauth2.sdk.GeneralException; 027import com.nimbusds.oauth2.sdk.OAuth2Error; 028import com.nimbusds.openid.connect.sdk.AuthenticationRequest; 029import com.nimbusds.openid.connect.sdk.ClaimsRequest; 030import com.nimbusds.openid.connect.sdk.claims.ACR; 031import com.nimbusds.openid.connect.sdk.claims.ClaimRequirement; 032import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation; 033import net.jcip.annotations.Immutable; 034 035 036/** 037 * Resolved authentication Context Class Reference (ACR) request. 038 */ 039@Immutable 040public final class ACRRequest { 041 042 043 /** 044 * The essential ACR values. 045 */ 046 private final List<ACR> essentialACRs; 047 048 049 /** 050 * The voluntary ACR values. 051 */ 052 private final List<ACR> voluntaryACRs; 053 054 055 /** 056 * Creates a new Authentication Context Class Reference (ACR) request. 057 * 058 * @param essentialACRs The requested essential ACR values, by order of 059 * preference, {@code null} if not specified. 060 * @param voluntaryACRs The requested voluntary ACR values, by order of 061 * preference, {@code null} if not specified. 062 */ 063 public ACRRequest(final List<ACR> essentialACRs, final List<ACR> voluntaryACRs) { 064 065 this.essentialACRs = essentialACRs; 066 this.voluntaryACRs = voluntaryACRs; 067 } 068 069 070 /** 071 * Gets the requested essential ACR values. 072 * 073 * @return The essential ACR values, by order of preference, 074 * {@code null} if not specified. 075 */ 076 public List<ACR> getEssentialACRs() { 077 078 return essentialACRs; 079 } 080 081 082 /** 083 * Gets the requested voluntary ACR values. 084 * 085 * @return The voluntary ACR values, by order of preference, 086 * {@code null} if not specified. 087 */ 088 public List<ACR> getVoluntaryACRs() { 089 090 return voluntaryACRs; 091 } 092 093 094 /** 095 * Checks if this ACR request has no essential or voluntary values 096 * specified. 097 * 098 * @return {@code true} if this ACR request doesn't specify any 099 * essential or voluntary values, else {@code false}. 100 */ 101 public boolean isEmpty() { 102 103 return !(essentialACRs != null && !essentialACRs.isEmpty()) && 104 !(voluntaryACRs != null && !voluntaryACRs.isEmpty()); 105 } 106 107 108 /** 109 * Applies the registered default ACR values for the requesting client 110 * (as a voluntary ACR value, provided no ACR values were explicitly 111 * requested). 112 * 113 * @param clientInfo The registered client information. Must not be 114 * {@code null}. 115 * 116 * @return The ACR request, updated if registered default ACR values 117 * were applied. 118 */ 119 public ACRRequest applyDefaultACRs(final OIDCClientInformation clientInfo) { 120 121 // Apply default ACR from client reg store as voluntary? 122 if (isEmpty()) { 123 if (clientInfo.getOIDCMetadata().getDefaultACRs() != null) { 124 List<ACR> voluntaryACRs = new LinkedList<>(clientInfo.getOIDCMetadata().getDefaultACRs()); 125 return new ACRRequest(null, voluntaryACRs); 126 } 127 } 128 129 return this; 130 } 131 132 133 /** 134 * Ensures all requested essential ACR values are supported by those 135 * supported by the OpenID provider. 136 * 137 * @param authzRequest The OAuth 2.0 authorisation request / OpenID 138 * authentication request. Must not be 139 * {@code null}. 140 * @param supportedACRs The ACR values supported by the OpenID 141 * provider, {@code null} if not specified. 142 * 143 * @throws GeneralException If a requested essential ACR value is not 144 * supported by the OpenID provider. 145 */ 146 public void ensureACRSupport(final AuthorizationRequest authzRequest, final List<ACR> supportedACRs) 147 throws GeneralException { 148 149 // Ensure any requested essential ACR is supported 150 if (getEssentialACRs() != null) { 151 152 boolean foundSupportedEssentialACR = false; 153 154 for (ACR acr: getEssentialACRs()) { 155 156 if (supportedACRs != null && supportedACRs.contains(acr)) { 157 foundSupportedEssentialACR = true; 158 break; 159 } 160 } 161 162 if (! foundSupportedEssentialACR) { 163 String msg = "Requested essential ACR(s) not supported"; 164 throw new GeneralException(msg, 165 OAuth2Error.ACCESS_DENIED.appendDescription(": " + msg), 166 authzRequest.getClientID(), 167 authzRequest.getRedirectionURI(), 168 authzRequest.impliedResponseMode(), 169 authzRequest.getState()); 170 } 171 } 172 } 173 174 175 /** 176 * Ensures all requested essential ACR values are supported by the 177 * OpenID provider. 178 * 179 * @param authRequest The OpenID authentication request. Must not be 180 * {@code null}. 181 * @param opMetadata The OpenID provider metadata. Must not be 182 * {@code null}. 183 * 184 * @throws GeneralException If a requested essential ACR value is not 185 * supported by the OpenID provider. 186 */ 187 @Deprecated 188 public void ensureACRSupport(final AuthenticationRequest authRequest, final OIDCProviderMetadata opMetadata) 189 throws GeneralException { 190 191 ensureACRSupport(authRequest, opMetadata.getACRs()); 192 } 193 194 195 /** 196 * Resolves the requested essential and voluntary ACR values from the 197 * specified OAuth 2.0 authorisation request / OpenID authentication 198 * request. 199 * 200 * @param authzRequest The OAuth 2.0 authorisation request / OpenID 201 * authentication request. Should be resolved. Must 202 * not be {@code null}. 203 * 204 * @return The resolved ACR request. 205 */ 206 public static ACRRequest resolve(final AuthorizationRequest authzRequest) { 207 208 List<ACR> essentialACRs = null; 209 List<ACR> voluntaryACRs = null; 210 211 if (! (authzRequest instanceof AuthenticationRequest)) { 212 // Plain OAuth 2.0 213 return new ACRRequest(essentialACRs, voluntaryACRs); 214 } 215 216 // OpenID 217 AuthenticationRequest authRequest = (AuthenticationRequest) authzRequest; 218 219 ClaimsRequest claimsRequest = authRequest.getClaims(); 220 221 if (claimsRequest != null) { 222 223 for (ClaimsRequest.Entry claimEntry: claimsRequest.getIDTokenClaims()) { 224 225 if (! claimEntry.getClaimName().equals("acr")) 226 continue; 227 228 if (claimEntry.getClaimRequirement().equals(ClaimRequirement.ESSENTIAL)) { 229 230 essentialACRs = new ArrayList<>(); 231 232 if (claimEntry.getValue() != null) 233 essentialACRs.add(new ACR(claimEntry.getValue())); 234 235 if (claimEntry.getValues() != null) { 236 237 for (String v: claimEntry.getValues()) 238 essentialACRs.add(new ACR(v)); 239 } 240 241 } else { 242 voluntaryACRs = new ArrayList<>(); 243 244 if (claimEntry.getValue() != null) 245 voluntaryACRs.add(new ACR(claimEntry.getValue())); 246 247 if (claimEntry.getValues() != null) { 248 249 for (String v: claimEntry.getValues()) 250 voluntaryACRs.add(new ACR(v)); 251 } 252 } 253 } 254 } 255 256 257 List<ACR> topLevelACRs = authRequest.getACRValues(); 258 259 if (topLevelACRs != null) { 260 261 if (voluntaryACRs == null) 262 voluntaryACRs = new ArrayList<>(); 263 264 voluntaryACRs.addAll(topLevelACRs); 265 } 266 267 return new ACRRequest(essentialACRs, voluntaryACRs); 268 } 269}