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