001    package com.nimbusds.oauth2.sdk;
002    
003    
004    import java.net.URL;
005    import java.util.LinkedHashMap;
006    import java.util.Map;
007    
008    import net.jcip.annotations.Immutable;
009    
010    import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
011    import com.nimbusds.oauth2.sdk.token.RefreshToken;
012    import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
013    import com.nimbusds.oauth2.sdk.http.HTTPRequest;
014    import com.nimbusds.oauth2.sdk.util.URLUtils;
015    
016    
017    /**
018     * Refresh token request to the Token endpoint. Used to refresh an 
019     * {@link com.nimbusds.oauth2.sdk.token.AccessToken access token}. This class 
020     * is immutable.
021     *
022     * <p>Note that the optional scope parameter is not supported.
023     *
024     * <p>Example refresh token request:
025     *
026     * <pre>
027     * POST /token HTTP/1.1
028     * Host: server.example.com
029     * Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
030     * Content-Type: application/x-www-form-urlencoded;charset=UTF-8
031     *
032     * grant_type=refresh_token&amp;refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
033     * </pre>
034     *
035     * <p>Related specifications:
036     *
037     * <ul>
038     *     <li>OAuth 2.0 (RFC 6749), section 6.
039     * </ul>
040     *
041     * @author Vladimir Dzhuvinov
042     */
043    @Immutable
044    public final class RefreshTokenRequest extends TokenRequest {
045    
046    
047            /**
048             * The refresh token.
049             */
050            private final RefreshToken refreshToken;
051            
052            
053            /**
054             * Creates a new unauthenticated refresh 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 refreshToken The refresh token. Must not be {@code null}.
060             */
061            public RefreshTokenRequest(final URL uri, final RefreshToken refreshToken) {
062            
063                    this(uri, refreshToken, null);
064            }
065            
066             
067            /**
068             * Creates a new authenticated refresh token request.
069             *
070             * @param uri          The URI of the token endpoint. May be 
071             *                     {@code null} if the {@link #toHTTPRequest()}
072             *                     method will not be used.
073             * @param refreshToken The refresh token. Must not be {@code null}.
074             * @param clientAuth   The client authentication, {@code null} if none.
075             */
076            public RefreshTokenRequest(final URL uri,
077                                       final RefreshToken refreshToken, 
078                                       final ClientAuthentication clientAuth) {
079            
080                    super(uri, GrantType.REFRESH_TOKEN, clientAuth);
081                    
082                    if (refreshToken == null)
083                            throw new IllegalArgumentException("The refresh token must not be null");
084                    
085                    this.refreshToken = refreshToken;
086            }
087            
088            
089            /**
090             * Gets the refresh token.
091             *
092             * @return The refresh token.
093             */
094            public RefreshToken getRefreshToken() {
095            
096                    return refreshToken;
097            }
098            
099            
100            @Override
101            public HTTPRequest toHTTPRequest()
102                    throws SerializeException {
103                    
104                    if (getURI() == null)
105                            throw new SerializeException("The endpoint URI is not specified");
106                    
107                    HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, getURI());
108                    
109                    httpRequest.setContentType(CommonContentTypes.APPLICATION_URLENCODED);
110                    
111                    Map<String,String> params = new LinkedHashMap<String,String>();
112                    params.put("grant_type", getGrantType().toString());
113                    params.put("refresh_token", refreshToken.getValue());
114                    
115                    httpRequest.setQuery(URLUtils.serializeParameters(params));
116                    
117                    if (getClientAuthentication() != null)
118                            getClientAuthentication().applyTo(httpRequest);
119                    
120                    return httpRequest;
121            }
122            
123            
124            /**
125             * Parses the specified HTTP request for a refresh token request.
126             *
127             * @param httpRequest The HTTP request. Must not be {@code null}.
128             *
129             * @return The refresh token request.
130             *
131             * @throws ParseException If the HTTP request couldn't be parsed to a 
132             *                        refresh token request.
133             */
134            public static RefreshTokenRequest parse(final HTTPRequest httpRequest)
135                    throws ParseException {
136                    
137                    // Only HTTP POST accepted
138                    httpRequest.ensureMethod(HTTPRequest.Method.POST);
139                    httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED);
140                    
141                    // No fragment!
142                    // May use query component!
143                    
144                    Map<String,String> params = httpRequest.getQueryParameters();
145                    
146                    
147                    // Parse grant type
148                    String grantTypeString = params.get("grant_type");
149                    
150                    if (grantTypeString == null)
151                            throw new ParseException("Missing \"grant_type\" parameter");
152    
153                    GrantType grantType = new GrantType(grantTypeString);
154                            
155                    if (! grantType.equals(GrantType.REFRESH_TOKEN))
156                            throw new ParseException("Invalid \"grant_type\" parameter: " + grantTypeString);
157                    
158                    
159                    // Parse refresh token
160                    String tokenString = params.get("refresh_token");
161                    
162                    if (tokenString == null)
163                            throw new ParseException("Missing \"refresh_token\" parameter");
164                    
165                    // Parse client authentication
166                    ClientAuthentication clientAuth = ClientAuthentication.parse(httpRequest);
167                    
168                    return new RefreshTokenRequest(URLUtils.getBaseURL(httpRequest.getURL()), 
169                                                   new RefreshToken(tokenString), clientAuth);
170            }
171    }