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.oauth2.sdk; 019 020 021import java.util.*; 022 023import net.jcip.annotations.Immutable; 024import net.jcip.annotations.NotThreadSafe; 025 026import com.nimbusds.oauth2.sdk.id.Identifier; 027 028 029/** 030 * Authorisation scope. 031 * 032 * <p>Example scope from OpenID Connect indicating access to the user's email 033 * and profile details: 034 * 035 * <pre> 036 * Scope scope = new Scope(); 037 * scope.add(OIDCScopeValue.OPENID); 038 * scope.add(OIDCScopeValue.EMAIL); 039 * scope.add(OIDCScopeValue.PROFILE); 040 * </pre> 041 * 042 * <p>Related specifications: 043 * 044 * <ul> 045 * <li>OAuth 2.0 (RFC 6749), section 3.3. 046 * </ul> 047 */ 048@NotThreadSafe 049public class Scope extends LinkedHashSet<Scope.Value> { 050 051 052 /** 053 * Authorisation scope value. 054 */ 055 @Immutable 056 public static class Value extends Identifier { 057 058 059 /** 060 * Enumeration of the scope value requirements for 061 * application-specific authorisation requests. 062 */ 063 public enum Requirement { 064 065 066 /** 067 * The value must be present in the {@link Scope} 068 * parameter. 069 */ 070 REQUIRED, 071 072 073 /** 074 * The value may be optionally included in the 075 * {@link Scope} parameter. 076 */ 077 OPTIONAL 078 } 079 080 081 /** 082 * Optional requirement. 083 */ 084 private final Value.Requirement requirement; 085 086 087 /** 088 * Creates a new scope value. The requirement is not specified. 089 * 090 * @param value The scope value. Must not be {@code null} or 091 * empty string. 092 */ 093 public Value(final String value) { 094 095 this(value, null); 096 } 097 098 /** 099 * Creates a new scope value with an optional requirement. 100 * 101 * @param value The scope value. Must not be {@code null} 102 * or empty string. 103 * @param requirement The requirement, {@code null} if not 104 * specified. 105 */ 106 public Value(final String value, final Requirement requirement) { 107 108 super(value); 109 110 this.requirement = requirement; 111 } 112 113 114 /** 115 * Gets the requirement of this scope value. 116 * 117 * @return The requirement, {@code null} if not specified. 118 */ 119 public Requirement getRequirement() { 120 121 return requirement; 122 } 123 124 125 @Override 126 public boolean equals(final Object object) { 127 128 return object instanceof Value && 129 this.toString().equals(object.toString()); 130 } 131 } 132 133 134 /** 135 * Creates a new empty authorisation scope. 136 */ 137 public Scope() { 138 // Nothing to do 139 } 140 141 142 /** 143 * Creates a new scope from the specified scope. 144 * 145 * @param scope The scope. May be {@code null}. 146 */ 147 public Scope(final Scope scope) { 148 149 if (scope == null) { 150 return; 151 } 152 153 addAll(scope); 154 } 155 156 157 /** 158 * Creates a new authorisation scope with the specified string values. 159 * 160 * @param values The string values. 161 */ 162 public Scope(final String ... values) { 163 164 for (String v: values) 165 add(new Value(v)); 166 } 167 168 169 /** 170 * Creates a new authorisation scope with the specified values. 171 * 172 * @param values The values. 173 */ 174 public Scope(final Value ... values) { 175 176 addAll(Arrays.asList(values)); 177 } 178 179 180 /** 181 * Adds the specified string value to this scope. 182 * 183 * @param value The string value. Must not be {@code null}. 184 * 185 * @return {@code true} if this scope did not already contain the 186 * specified value. 187 */ 188 public boolean add(final String value) { 189 190 return add(new Value(value)); 191 } 192 193 194 /** 195 * Checks if this scope contains the specified string value. 196 * 197 * @param value The string value. Must not be {@code null}. 198 * 199 * @return {@code true} if the value is contained, else {@code false}. 200 */ 201 public boolean contains(final String value) { 202 203 return contains(new Value(value)); 204 } 205 206 207 /** 208 * Returns the string representation of this scope. The scope values 209 * will be serialised in the order they were added. 210 * 211 * @return The string representation. 212 */ 213 @Override 214 public String toString() { 215 216 StringBuilder sb = new StringBuilder(); 217 218 for (Scope.Value v : this) { 219 220 if (sb.length() > 0) { 221 sb.append(' '); 222 } 223 224 sb.append(v.toString()); 225 } 226 227 return sb.toString(); 228 } 229 230 231 /** 232 * Returns the string list representation of this scope. The scope 233 * values will be serialised in the order they were added. 234 * 235 * @return The string list representation. 236 */ 237 public List<String> toStringList() { 238 239 List<String> list = new ArrayList<>(this.size()); 240 241 for (Scope.Value v: this) 242 list.add(v.getValue()); 243 244 return list; 245 } 246 247 248 /** 249 * Parses a scope from the specified string collection representation. 250 * 251 * @param collection The string collection, {@code null} if not 252 * specified. 253 * 254 * @return The scope, {@code null} if not specified. 255 */ 256 public static Scope parse(final Collection<String> collection) { 257 258 if (collection == null) 259 return null; 260 261 Scope scope = new Scope(); 262 263 for (String v: collection) 264 scope.add(new Scope.Value(v)); 265 266 return scope; 267 } 268 269 270 /** 271 * Parses a scope from the specified string representation. 272 * 273 * @param s The scope string, {@code null} if not specified. 274 * 275 * @return The scope, {@code null} if not specified. 276 */ 277 public static Scope parse(final String s) { 278 279 if (s == null) 280 return null; 281 282 Scope scope = new Scope(); 283 284 if (s.trim().isEmpty()) 285 return scope; 286 287 // OAuth specifies space as delimiter, also support comma (old draft) 288 StringTokenizer st = new StringTokenizer(s, " ,"); 289 290 while(st.hasMoreTokens()) 291 scope.add(new Scope.Value(st.nextToken())); 292 293 return scope; 294 } 295}