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; 019 020 021import java.util.Arrays; 022import java.util.Collections; 023import java.util.HashSet; 024import java.util.LinkedHashSet; 025import java.util.Set; 026 027import net.minidev.json.JSONObject; 028 029import com.nimbusds.oauth2.sdk.Scope; 030 031import com.nimbusds.openid.connect.sdk.claims.ClaimRequirement; 032 033 034/** 035 * Standard OpenID Connect scope value. 036 * 037 * <p>Related specifications: 038 * 039 * <ul> 040 * <li>OpenID Connect Core 1.0, section 5.2. 041 * </ul> 042 */ 043public class OIDCScopeValue extends Scope.Value { 044 045 046 /** 047 * Informs the authorisation server that the client is making an OpenID 048 * Connect request (REQUIRED). This scope value requests access to the 049 * {@code sub} claim. 050 */ 051 public static final OIDCScopeValue OPENID = 052 new OIDCScopeValue("openid", Scope.Value.Requirement.REQUIRED, new String[]{"sub"}); 053 054 055 /** 056 * Requests that access to the end-user's default profile claims at the 057 * UserInfo endpoint be granted by the issued access token. These 058 * claims are: {@code name}, {@code family_name}, {@code given_name}, 059 * {@code middle_name}, {@code nickname}, {@code preferred_username}, 060 * {@code profile}, {@code picture}, {@code website}, {@code gender}, 061 * {@code birthdate}, {@code zoneinfo}, {@code locale}, and 062 * {@code updated_at}. 063 */ 064 public static final OIDCScopeValue PROFILE = 065 new OIDCScopeValue("profile", new String[]{"name", 066 "family_name", 067 "given_name", 068 "middle_name", 069 "nickname", 070 "preferred_username", 071 "profile", 072 "picture", 073 "website", 074 "gender", 075 "birthdate", 076 "zoneinfo", 077 "locale", 078 "updated_at"}); 079 080 081 /** 082 * Requests that access to the {@code email} and {@code email_verified} 083 * claims at the UserInfo endpoint be granted by the issued access 084 * token. 085 */ 086 public static final OIDCScopeValue EMAIL = 087 new OIDCScopeValue("email", new String[]{"email", "email_verified"}); 088 089 090 /** 091 * Requests that access to {@code address} claim at the UserInfo 092 * endpoint be granted by the issued access token. 093 */ 094 public static final OIDCScopeValue ADDRESS = 095 new OIDCScopeValue("address", new String[]{"address"}); 096 097 098 /** 099 * Requests that access to the {@code phone_number} and 100 * {@code phone_number_verified} claims at the UserInfo endpoint be 101 * granted by the issued access token. 102 */ 103 public static final OIDCScopeValue PHONE = 104 new OIDCScopeValue("phone", new String[]{"phone_number", 105 "phone_number_verified"}); 106 107 108 /** 109 * Requests that an OAuth 2.0 refresh token be issued that can be used 110 * to obtain an access token that grants access the end-user's UserInfo 111 * endpoint even when the user is not present (not logged in). 112 */ 113 public static final OIDCScopeValue OFFLINE_ACCESS = 114 new OIDCScopeValue("offline_access", null); 115 116 117 /** 118 * Returns the standard OpenID Connect scope values declared in this 119 * class. 120 * 121 * @return The standard OpenID Connect scope values. 122 */ 123 public static OIDCScopeValue[] values() { 124 125 return new OIDCScopeValue[]{ OPENID, PROFILE, EMAIL, ADDRESS, PHONE, OFFLINE_ACCESS }; 126 } 127 128 129 /** 130 * The names of the associated claims, {@code null} if not applicable. 131 */ 132 private final Set<String> claims; 133 134 135 /** 136 * Creates a new OpenID Connect scope value. 137 * 138 * @param value The scope value. Must not be {@code null}. 139 * @param requirement The requirement. Must not be {@code null}. 140 * @param claims The names of the associated claims, {@code null} 141 * if not applicable. 142 */ 143 private OIDCScopeValue(final String value, 144 final Scope.Value.Requirement requirement, 145 final String[] claims) { 146 147 super(value, requirement); 148 149 if (claims != null) 150 this.claims = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(claims))); 151 else 152 this.claims = null; 153 } 154 155 156 /** 157 * Creates a new OpenID Connect scope value. The requirement is set to 158 * {@link OIDCScopeValue.Requirement#OPTIONAL optional}. 159 * 160 * @param value The scope value. Must not be {@code null}. 161 * @param claims The names of the associated claims. Must not be 162 * {@code null}. 163 */ 164 private OIDCScopeValue(final String value, 165 final String[] claims) { 166 167 this(value, Scope.Value.Requirement.OPTIONAL, claims); 168 } 169 170 171 /** 172 * Returns the names of the associated claims. 173 * 174 * @return The names of the associated claims, {@code null} if not 175 * applicable. 176 */ 177 public Set<String> getClaimNames() { 178 179 return claims; 180 } 181 182 183 /** 184 * Gets the claims request JSON object for this OpenID Connect scope 185 * value. 186 * 187 * <p>See OpenID Connect Core 1.0, section 5.1. 188 * 189 * <p>Example JSON object for "openid" scope value: 190 * 191 * <pre> 192 * { 193 * "sub" : { "essential" : true } 194 * } 195 * </pre> 196 * 197 * <p>Example JSON object for "email" scope value: 198 * 199 * <pre> 200 * { 201 * "email" : null, 202 * "email_verified" : null 203 * } 204 * </pre> 205 * 206 * @return The claims request JSON object, {@code null} if not 207 * applicable. 208 */ 209 public JSONObject toClaimsRequestJSONObject() { 210 211 JSONObject req = new JSONObject(); 212 213 if (claims == null) 214 return null; 215 216 for (String claim: claims) { 217 218 if (getRequirement() == Scope.Value.Requirement.REQUIRED) { 219 220 // Essential (applies to OPENID - sub only) 221 JSONObject details = new JSONObject(); 222 details.put("essential", true); 223 req.put(claim, details); 224 225 } else { 226 // Voluntary 227 req.put(claim, null); 228 } 229 } 230 231 return req; 232 } 233 234 235 /** 236 * Gets the claims request entries for this OpenID Connect scope value. 237 * 238 * <p>See OpenID Connect Core 1.0, section 5.1. 239 * 240 * @return The claims request entries, {@code null} if not applicable 241 * (for scope values {@link #OPENID} and 242 * {@link #OFFLINE_ACCESS}). 243 */ 244 public Set<ClaimsRequest.Entry> toClaimsRequestEntries() { 245 246 Set<ClaimsRequest.Entry> entries = new HashSet<>(); 247 248 if (this == OPENID || this == OFFLINE_ACCESS) 249 return Collections.unmodifiableSet(entries); 250 251 for (String claimName: getClaimNames()) 252 entries.add(new ClaimsRequest.Entry(claimName, ClaimRequirement.VOLUNTARY)); 253 254 return Collections.unmodifiableSet(entries); 255 } 256}