001    package com.nimbusds.openid.connect.sdk;
002    
003    
004    import java.net.URL;
005    import java.util.Map;
006    
007    import net.jcip.annotations.Immutable;
008    
009    import com.nimbusds.oauth2.sdk.ParseException;
010    import com.nimbusds.oauth2.sdk.Request;
011    import com.nimbusds.oauth2.sdk.SerializeException;
012    import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
013    import com.nimbusds.oauth2.sdk.http.HTTPRequest;
014    import com.nimbusds.oauth2.sdk.token.AccessToken;
015    
016    
017    /**
018     * UserInfo request. Used to retrieve requested claims about the end-user. This
019     * class is immutable.
020     *
021     * <p>Example HTTP GET request:
022     *
023     * <pre>
024     * GET /userinfo?schema=openid HTTP/1.1
025     * Host: server.example.com
026     * Authorization: Bearer mF_9.B5f-4.1JqM
027     * </pre>
028     *
029     * <p>Example HTTP POST request:
030     *
031     * <pre>
032     * POST /userinfo HTTP/1.1
033     * Host: server.example.com
034     * Content-Type: application/x-www-form-urlencoded
035     *
036     * schema=openid&amp;access_token=mF_9.B5f-4.1JqM
037     * </pre>
038     *
039     * <p>Related specifications:
040     *
041     * <ul>
042     *     <li>OpenID Connect Messages 1.0, section 2.3.1.
043     *     <li>OpenID Connect Standard 1.0, section 4.1.
044     *     <li>OAuth 2.0 Bearer Token Usage (RFC6750), section 2.
045     * </ul>
046     *
047     * @author Vladimir Dzhuvinov
048     * @version $version$ (2013-05-10)
049     */
050    @Immutable
051    public final class UserInfoRequest implements Request {
052    
053    
054            /**
055             * The HTTP method.
056             */
057            private final HTTPRequest.Method httpMethod;
058             
059             
060            /**
061             * The UserInfo access token.
062             */
063            private final AccessToken accessToken;
064            
065            
066            /**
067             * Creates a new UserInfo HTTP GET request.
068             *
069             * @param accessToken The UserInfo access token. Must not be 
070             *                    {@code null}.
071             */
072            public UserInfoRequest(final AccessToken accessToken) {
073            
074                    this(HTTPRequest.Method.GET, accessToken);
075            }
076            
077            
078            /**
079             * Creates a new UserInfo request.
080             *
081             * @param httpMethod  The HTTP method. Must be HTTP GET or POST and not 
082             *                    {@code null}.
083             * @param accessToken The UserInfo access token. Must not be
084             *                    {@code null}.
085             */
086            public UserInfoRequest(final HTTPRequest.Method httpMethod, final AccessToken accessToken) {
087            
088                    if (httpMethod == null)
089                            throw new IllegalArgumentException("The HTTP method must not be null");
090                    
091                    this.httpMethod = httpMethod;
092                    
093                    
094                    if (accessToken == null)
095                            throw new IllegalArgumentException("The access token must not be null");
096                    
097                    this.accessToken = accessToken;
098            }
099            
100            
101            /**
102             * Gets the HTTP method for this UserInfo request.
103             *
104             * @return The HTTP method.
105             */
106            public HTTPRequest.Method getMethod() {
107            
108                    return httpMethod;
109            }
110            
111            
112            /**
113             * Gets the UserInfo access token.
114             *
115             * @return The UserInfo access token.
116             */
117            public AccessToken getAccessToken() {
118            
119                    return accessToken;
120            }
121            
122            
123            @Override
124            public HTTPRequest toHTTPRequest(final URL url)
125                    throws SerializeException {
126            
127                    HTTPRequest httpRequest = new HTTPRequest(httpMethod, url);
128                    
129                    switch (httpMethod) {
130                    
131                            case GET:
132                                    httpRequest.setAuthorization(accessToken.toAuthorizationHeader());      
133                                    httpRequest.setQuery("schema=openid");
134                                    break;
135                                    
136                            case POST:
137                                    httpRequest.setContentType(CommonContentTypes.APPLICATION_URLENCODED);
138                                    httpRequest.setQuery("schema=openid" +
139                                                         "&access_token=" + accessToken.getValue());
140                                    break;
141                            
142                            default:
143                                    throw new SerializeException("Unexpected HTTP method: " + httpMethod);
144                    }
145                    
146                    return httpRequest;
147            }
148            
149            
150            /**
151             * Parses the specified HTTP request for a UserInfo request.
152             *
153             * @param httpRequest The HTTP request. Must not be {@code null}.
154             *
155             * @return The UserInfo request.
156             *
157             * @throws ParseException If the HTTP request couldn't be parsed to a 
158             *                        UserInfo request.
159             */
160            public static UserInfoRequest parse(final HTTPRequest httpRequest)
161                    throws ParseException {
162                    
163                    HTTPRequest.Method httpMethod = httpRequest.getMethod();
164                    
165                    AccessToken accessToken = null;
166                    
167                    switch (httpMethod) {
168                    
169                            case GET:
170                            
171                                    String authzHeader = httpRequest.getAuthorization();
172                                    
173                                    if (authzHeader == null)
174                                            throw new ParseException("Missing HTTP Authorization header");
175                                    
176                                    accessToken = AccessToken.parse(authzHeader);
177                                    
178                                    String query = httpRequest.getQuery();
179                                    
180                                    if (query == null)
181                                            throw new ParseException("Missing query string");
182                                    
183                                    if (query.indexOf("schema=openid") < 0)
184                                            throw new ParseException("Missing or unexpected schema parameter, must be \"openid\"");
185                                    
186                                    break;
187                                    
188                                    
189                            case POST:
190                            
191                                    httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED);
192                                    
193                                    Map<String,String> params = httpRequest.getQueryParameters();     
194                            
195                                    if (! params.containsKey("schema"))
196                                            throw new ParseException("Missing schema parameter");
197                                    
198                                    if ("openid".equals(params.get("schema")))
199                                            throw new ParseException("Unexpected schema parameter, must be \"openid\"");
200                            
201                                    if (! params.containsKey("access_token"))
202                                            throw new ParseException("Missing access_token parameter");
203                                    
204                                    accessToken = AccessToken.parse(params.get("access_token"));
205                            
206                                    break;
207                            
208                            default:
209                                    throw new ParseException("Unexpected HTTP method: " + httpMethod);
210                    }
211            
212                    return new UserInfoRequest(httpMethod, accessToken);
213            }
214    }