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.*; 022 023import com.nimbusds.oauth2.sdk.ParseException; 024import com.nimbusds.oauth2.sdk.util.StringUtils; 025import net.jcip.annotations.NotThreadSafe; 026 027 028/** 029 * Prompts for end-user re-authentication and consent. 030 * 031 * <p>Related specifications: 032 * 033 * <ul> 034 * <li>OpenID Connect Core 1.0, section 3.1.2.1. 035 * </ul> 036 */ 037@NotThreadSafe 038public class Prompt extends LinkedHashSet<Prompt.Type> { 039 040 041 /** 042 * Enumeration of the prompt types. 043 */ 044 public enum Type { 045 046 047 /** 048 * The authorisation server must not display any authentication 049 * or consent UI pages. An error is returned if the end user is 050 * not already authenticated or the client does not have 051 * pre-configured consent for the requested {@code scope}. This 052 * can be used as a method to check for existing authentication 053 * and / or consent. 054 */ 055 NONE, 056 057 058 /** 059 * The authorisation server must prompt the end-user for 060 * re-authentication. 061 */ 062 LOGIN, 063 064 065 /** 066 * The authorisation server must prompt the end-user for 067 * consent before returning information to the client. 068 */ 069 CONSENT, 070 071 072 /** 073 * The authorisation server must prompt the end-user to select 074 * a user account. This allows a user who has multiple accounts 075 * at the authorisation server to select amongst the multiple 076 * accounts that they may have current sessions for. 077 */ 078 SELECT_ACCOUNT; 079 080 081 /** 082 * Returns the string identifier of this prompt type. 083 * 084 * @return The string identifier. 085 */ 086 @Override 087 public String toString() { 088 089 return super.toString().toLowerCase(); 090 } 091 092 093 /** 094 * Parses a prompt type. 095 * 096 * @param s The string to parse. 097 * 098 * @return The prompt type. 099 * 100 * @throws ParseException If the parsed string is {@code null} 101 * or doesn't match a prompt type. 102 */ 103 public static Type parse(final String s) 104 throws ParseException { 105 106 if (StringUtils.isBlank(s)) 107 throw new ParseException("Null or empty prompt type string"); 108 109 if ("none".equals(s)) { 110 return NONE; 111 } else if ("login".equals(s)) { 112 return LOGIN; 113 } else if ("consent".equals(s)) { 114 return CONSENT; 115 } else if ("select_account".equals(s)) { 116 return SELECT_ACCOUNT; 117 } else { 118 throw new ParseException("Unknown prompt type: " + s); 119 } 120 } 121 } 122 123 124 /** 125 * Creates a new empty prompt. 126 */ 127 public Prompt() { 128 129 // Nothing to do 130 } 131 132 133 /** 134 * Creates a new prompt with the specified types. 135 * 136 * @param type The prompt types. 137 */ 138 public Prompt(final Type ... type) { 139 140 addAll(Arrays.asList(type)); 141 } 142 143 144 /** 145 * Creates a new prompt with the specified type values. 146 * 147 * @param values The prompt type values. 148 * 149 * @throws java.lang.IllegalArgumentException If the type value is 150 * invalid. 151 */ 152 public Prompt(final String ... values) { 153 154 for (String v: values) { 155 156 try { 157 add(Type.parse(v)); 158 159 } catch (ParseException e) { 160 161 throw new IllegalArgumentException(e.getMessage(), e); 162 } 163 } 164 } 165 166 167 /** 168 * Checks if the prompt is valid. This is done by examining the prompt 169 * for a conflicting {@link Type#NONE} value. 170 * 171 * @return {@code true} if this prompt if valid, else {@code false}. 172 */ 173 public boolean isValid() { 174 175 return !(size() > 1 && contains(Type.NONE)); 176 } 177 178 179 /** 180 * Returns the string list representation of this prompt. 181 * 182 * @return The string list representation. 183 */ 184 public List<String> toStringList() { 185 186 List<String> list = new ArrayList<>(this.size()); 187 188 for (Type t: this) 189 list.add(t.toString()); 190 191 return list; 192 } 193 194 195 /** 196 * Returns the string representation of this prompt. The values are 197 * delimited by space. 198 * 199 * <p>Example: 200 * 201 * <pre> 202 * login consent 203 * </pre> 204 * 205 * @return The string representation. 206 */ 207 @Override 208 public String toString() { 209 210 StringBuilder sb = new StringBuilder(); 211 212 Iterator<Type> it = super.iterator(); 213 214 while (it.hasNext()) { 215 216 sb.append(it.next().toString()); 217 218 if (it.hasNext()) 219 sb.append(" "); 220 } 221 222 return sb.toString(); 223 } 224 225 226 /** 227 * Parses a prompt from the specified string list. 228 * 229 * @param collection The string list to parse, with one or more 230 * non-conflicting prompt types. May be {@code null}. 231 * 232 * @return The prompt, {@code null} if the parsed string list was 233 * {@code null} or empty. 234 * 235 * @throws ParseException If the string list couldn't be parsed to a 236 * valid prompt. 237 */ 238 public static Prompt parse(final Collection<String> collection) 239 throws ParseException { 240 241 if (collection == null) 242 return null; 243 244 Prompt prompt = new Prompt(); 245 246 for (String s: collection) 247 prompt.add(Prompt.Type.parse(s)); 248 249 if (! prompt.isValid()) 250 throw new ParseException("Invalid prompt: " + collection); 251 252 return prompt; 253 } 254 255 256 /** 257 * Parses a prompt from the specified string. 258 * 259 * @param s The string to parse, with one or more non-conflicting space 260 * delimited prompt types. May be {@code null}. 261 * 262 * @return The prompt, {@code null} if the parsed string was 263 * {@code null} or empty. 264 * 265 * @throws ParseException If the string couldn't be parsed to a valid 266 * prompt. 267 */ 268 public static Prompt parse(final String s) 269 throws ParseException { 270 271 if (StringUtils.isBlank(s)) 272 return null; 273 274 Prompt prompt = new Prompt(); 275 276 StringTokenizer st = new StringTokenizer(s, " "); 277 278 while (st.hasMoreTokens()) 279 prompt.add(Prompt.Type.parse(st.nextToken())); 280 281 if (! prompt.isValid()) 282 throw new ParseException("Invalid prompt: " + s); 283 284 return prompt; 285 } 286}