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.rp.OIDCClientInformation; 028import net.jcip.annotations.Immutable; 029 030import com.nimbusds.openid.connect.sdk.AuthenticationRequest; 031import com.nimbusds.openid.connect.sdk.ClaimsRequest; 032import com.nimbusds.openid.connect.sdk.claims.ACR; 033import com.nimbusds.openid.connect.sdk.claims.ClaimRequirement; 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 the 135 * OpenID provider. 136 * 137 * @param authRequest The OpenID authentication request. Must not be 138 * {@code null}. 139 * @param opMetadata The OpenID provider metadata. Must not be 140 * {@code null}. 141 * 142 * @throws GeneralException If a requested essential ACR value is not 143 * supported by the OpenID provider. 144 */ 145 public void ensureACRSupport(final AuthenticationRequest authRequest, final OIDCProviderMetadata opMetadata) 146 throws GeneralException { 147 148 // Ensure any requested essential ACR is supported 149 if (getEssentialACRs() != null) { 150 151 boolean foundSupportedEssentialACR = false; 152 153 for (ACR acr: getEssentialACRs()) { 154 155 if (opMetadata.getACRs() != null && opMetadata.getACRs().contains(acr)) { 156 foundSupportedEssentialACR = true; 157 break; 158 } 159 } 160 161 if (! foundSupportedEssentialACR) { 162 String msg = "Requested essential ACR(s) not supported"; 163 throw new GeneralException(msg, 164 OAuth2Error.ACCESS_DENIED.appendDescription(": " + msg), 165 authRequest.getClientID(), 166 authRequest.getRedirectionURI(), 167 authRequest.impliedResponseMode(), 168 authRequest.getState()); 169 } 170 } 171 } 172 173 174 /** 175 * Resolves the requested essential and voluntary ACR values from the 176 * specified OpenID authentication request. 177 * 178 * @param authRequest The OpenID authentication request. Should be 179 * resolved. Must not be {@code null}. 180 * 181 * @return The resolved ACR request. 182 */ 183 public static ACRRequest resolve(final AuthenticationRequest authRequest) { 184 185 List<ACR> essentialACRs = null; 186 List<ACR> voluntaryACRs = null; 187 188 ClaimsRequest claimsRequest = authRequest.getClaims(); 189 190 if (claimsRequest != null) { 191 192 for (ClaimsRequest.Entry claimEntry: claimsRequest.getIDTokenClaims()) { 193 194 if (! claimEntry.getClaimName().equals("acr")) 195 continue; 196 197 if (claimEntry.getClaimRequirement().equals(ClaimRequirement.ESSENTIAL)) { 198 199 essentialACRs = new ArrayList<>(); 200 201 if (claimEntry.getValue() != null) 202 essentialACRs.add(new ACR(claimEntry.getValue())); 203 204 if (claimEntry.getValues() != null) { 205 206 for (String v: claimEntry.getValues()) 207 essentialACRs.add(new ACR(v)); 208 } 209 210 } else { 211 voluntaryACRs = new ArrayList<>(); 212 213 if (claimEntry.getValue() != null) 214 voluntaryACRs.add(new ACR(claimEntry.getValue())); 215 216 if (claimEntry.getValues() != null) { 217 218 for (String v: claimEntry.getValues()) 219 voluntaryACRs.add(new ACR(v)); 220 } 221 } 222 } 223 } 224 225 226 List<ACR> topLevelACRs = authRequest.getACRValues(); 227 228 if (topLevelACRs != null) { 229 230 if (voluntaryACRs == null) 231 voluntaryACRs = new ArrayList<>(); 232 233 voluntaryACRs.addAll(topLevelACRs); 234 } 235 236 return new ACRRequest(essentialACRs, voluntaryACRs); 237 } 238}