001    package com.nimbusds.oauth2.sdk;
002    
003    
004    import java.net.URL;
005    import java.util.Map;
006    
007    import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
008    import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
009    import com.nimbusds.oauth2.sdk.http.HTTPRequest;
010    
011    
012    /**
013     * The base abstract class for access token and refresh token requests to the
014     * Token endpoint. The request type can be inferred by calling 
015     * {@link #getGrantType}.
016     *
017     * <p>Example access token request:
018     *
019     * <pre>
020     * POST /token HTTP/1.1
021     * Host: server.example.com
022     * Content-Type: application/x-www-form-urlencoded
023     * Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
024     * 
025     * grant_type=authorization_code
026     * &amp;code=SplxlOBeZQQYbYS6WxSbIA
027     * &amp;redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
028     * </pre>
029     *
030     * <p>Related specifications:
031     *
032     * <ul>
033     *     <li>OAuth 2.0 (RFC 6749), sections 4.1.3, .
034     * </ul>
035     *
036     * @author Vladimir Dzhuvinov
037     */
038    public abstract class TokenRequest extends AbstractRequest {
039    
040    
041            /**
042             * The grant type.
043             */
044            private final GrantType grantType;
045            
046            
047            /**
048             * The client authentication, {@code null} if none.
049             */
050            private final ClientAuthentication clientAuth;
051            
052            
053            /**
054             * Creates a new token request.
055             *
056             * @param uri        The URI of the token endpoint. May be 
057             *                   {@code null} if the {@link #toHTTPRequest()}
058             *                   method will not be used.
059             * @param grantType  The grant type. Must not be {@code null}.
060             * @param clientAuth The client authentication, {@code null} if none.
061             */
062            protected TokenRequest(final URL uri, 
063                                   final GrantType grantType, 
064                                   final ClientAuthentication clientAuth) {
065            
066                    super(uri);
067                    
068                    if (grantType == null)
069                            throw new IllegalArgumentException("The grant type must not be null");
070                    
071                    this.grantType = grantType;
072                    
073                    this.clientAuth = clientAuth;
074            }
075            
076            
077            /**
078             * Gets the grant type.
079             *
080             * @return The grant type.
081             */
082            public GrantType getGrantType() {
083            
084                    return grantType;
085            }
086            
087            
088            /**
089             * Gets the client authentication.
090             *
091             * @return The client authentication, {@code null} if none.
092             */
093            public ClientAuthentication getClientAuthentication() {
094            
095                    return clientAuth;
096            }
097            
098            
099            /**
100             * Parses the specified HTTP request for a token request.
101             *
102             * @param httpRequest The HTTP request. Must not be {@code null}.
103             *
104             * @return The token request.
105             *
106             * @throws ParseException If the HTTP request couldn't be parsed to a 
107             *                        token request.
108             */
109            public static TokenRequest parse(final HTTPRequest httpRequest)
110                    throws ParseException {
111                    
112                    // Only HTTP POST accepted
113                    httpRequest.ensureMethod(HTTPRequest.Method.POST);
114                    httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED);
115                    
116                    // No fragment!
117                    // May use query component!
118                    Map<String,String> params = httpRequest.getQueryParameters();
119                    
120                    
121                    // Parse grant type
122                    final String grantTypeString = params.get("grant_type");
123                    
124                    if (grantTypeString == null)
125                            throw new ParseException("Missing \"grant_type\" parameter");
126                    
127                    GrantType grantType = new GrantType(grantTypeString);
128                    
129                    if (grantType.equals(GrantType.AUTHORIZATION_CODE))
130                            return AccessTokenRequest.parse(httpRequest);
131    
132                    else if (grantType.equals(GrantType.REFRESH_TOKEN))
133                            return RefreshTokenRequest.parse(httpRequest);
134                    
135                    else
136                            throw new ParseException("Unsupported \"grant_type\": " + grantType);
137            }
138    }