001    package com.nimbusds.oauth2.sdk;
002    
003    
004    import java.util.HashSet;
005    import java.util.StringTokenizer;
006    
007    import net.jcip.annotations.Immutable;
008    import net.jcip.annotations.NotThreadSafe;
009    
010    import org.apache.commons.lang3.StringUtils;
011    
012    import com.nimbusds.oauth2.sdk.id.Identifier;
013    
014    
015    /**
016     * Authorisation response type. Can be single-valued or multiple-valued. This
017     * class is not thread-safe.
018     *
019     * <p>The following helper methods can be used to find out the OAuth 2.0
020     * protocol flow that a particular response type implies:
021     *
022     * <ul>
023     *     <li>{@link #impliesImplicitFlow}
024     *     <li>{@link #impliesCodeFlow}
025     * </ul>
026     *
027     * <p>Example response type implying an authorisation code flow:
028     *
029     * <pre>
030     * ResponseType() rt = new ResponseType();
031     * rt.add(ResponseType.Value.CODE);
032     * </pre>
033     *
034     * <p>Example response type from OpenID Connect specifying an ID token and an 
035     * access token (implies implicit flow):
036     *
037     * <pre>
038     * ResponseType() rt = new ResponseType();
039     * rt.add(OIDCResponseTypeValue.ID_TOKEN);
040     * rt.add(ResponseType.Value.TOKEN);
041     * </pre>
042     *
043     * <p>Related specifications:
044     *
045     * <ul>
046     *     <li>OAuth 2.0 (RFC 6749), sections 3.1.1 and 4.1.1.
047     *     <li>OAuth 2.0 Multiple Response Type Encoding Practices
048     * </ul>
049     *
050     * @author Vladimir Dzhuvinov
051     */
052    @NotThreadSafe
053    public class ResponseType extends HashSet<ResponseType.Value> {
054            
055            
056            /**
057             * Authorisation response type value. This class is immutable.
058             */
059            @Immutable
060            public static final class Value extends Identifier {
061    
062                    /**
063                     * Authorisation code.
064                     */
065                    public static final Value CODE = new Value("code");
066    
067                    
068                    /**
069                     * Access token, with optional refresh token.
070                     */
071                    public static final Value TOKEN = new Value("token");
072    
073                    
074                    /**
075                     * Creates a new response type value.
076                     *
077                     * @param value The response type value. Must not be
078                     *              {@code null} or empty string.
079                     */
080                    public Value(final String value) {
081    
082                            super(value);
083                    }
084                    
085                    
086                    @Override
087                    public boolean equals(final Object object) {
088    
089                            return object != null
090                                    && object instanceof Value
091                                    && this.toString().equals(object.toString());
092                    }
093            }
094    
095            
096            /**
097             *  Gets the default response type.
098             * 
099             * @return The default response type, consisting of the value
100             *         {@link ResponseType.Value#CODE}.
101             */
102            public static ResponseType getDefault() {
103                    
104                    ResponseType defaultResponseType = new ResponseType();
105                    defaultResponseType.add(ResponseType.Value.CODE);
106                    return defaultResponseType;
107            }
108    
109            
110            /**
111             * Creates a new empty response type.
112             */
113            public ResponseType() {
114                    
115            }
116            
117            
118            /**
119             * Parses a set of authorisation response types.
120             *
121             * <p>Example serialised response type sets:
122             *
123             * <pre>
124             * code
125             * token
126             * id_token
127             * id_token token
128             * code token
129             * code id_token
130             * code id_token token
131             * </pre>
132             *
133             * @param s Space-delimited list of one or more authorisation response 
134             *          types.
135             *
136             * @return The authorisation response types set.
137             *
138             * @throws ParseException If the parsed string is {@code null} or 
139             *                        empty.
140             */
141            public static ResponseType parse(final String s)
142                    throws ParseException {
143            
144                    if (StringUtils.isBlank(s))
145                            throw new ParseException("Null or empty response type string");
146            
147                    ResponseType rt = new ResponseType();
148                    
149                    StringTokenizer st = new StringTokenizer(s, " ");
150    
151                    while (st.hasMoreTokens())
152                            rt.add(new ResponseType.Value(st.nextToken()));
153                    
154                    return rt;
155            }
156            
157            
158            /**
159             * Returns {@code true} if this response type implies a code flow. This
160             * is determined by the presence of a {@code code} value.
161             *
162             * @return {@code true} if a code flow is implied, else {@code false}.
163             */
164            public boolean impliesCodeFlow() {
165            
166                    if (this.contains(ResponseType.Value.CODE))
167                            return true;
168                    else
169                            return false;
170            }
171            
172            
173            /**
174             * Returns {@code true} if this response type implies an implicit flow.
175             * This is determined by the absence of a {@code code} value.
176             *
177             * @return {@code true} if an implicit flow is implied, else 
178             *         {@code false}.
179             */
180            public boolean impliesImplicitFlow() {
181            
182                    return ! impliesCodeFlow();
183            }
184            
185            
186            /**
187             * Returns the string representation of this  authorisation response 
188             * type.
189             *
190             * <p>Example serialised response types:
191             *
192             * <pre>
193             * code
194             * token
195             * id_token
196             * id_token token
197             * code token
198             * code id_token
199             * code id_token token
200             * </pre>
201             *
202             * @return Space delimited string representing the authorisation 
203             *         response type.
204             */
205            @Override
206            public String toString() {
207            
208                    StringBuilder sb = new StringBuilder();
209    
210                    for (ResponseType.Value v: this) {
211    
212                            if (sb.length() > 0)
213                                    sb.append(' ');
214    
215                            sb.append(v.getValue());
216                    }
217    
218                    return sb.toString();
219            }
220    }