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.oauth2.sdk;
019
020
021import com.nimbusds.common.contenttype.ContentType;
022import com.nimbusds.oauth2.sdk.http.HTTPResponse;
023import com.nimbusds.oauth2.sdk.token.Tokens;
024import net.jcip.annotations.Immutable;
025import net.minidev.json.JSONObject;
026
027import java.util.*;
028
029
030/**
031 * Access token response from the Token endpoint.
032 *
033 * <p>Example HTTP response:
034 *
035 * <pre>
036 * HTTP/1.1 200 OK
037 * Content-Type: application/json;charset=UTF-8
038 * Cache-Control: no-store
039 * Pragma: no-cache
040 *
041 * {
042 *   "access_token"      : "2YotnFZFEjr1zCsicMWpAA",
043 *   "token_type"        : "example",
044 *   "expires_in"        : 3600,
045 *   "refresh_token"     : "tGzv3JOkF0XG5Qx2TlKWIA",
046 *   "example_parameter" : "example_value"
047 * }
048 * </pre>
049 *
050 * <p>Related specifications:
051 *
052 * <ul>
053 *     <li>OAuth 2.0 (RFC 6749)
054 * </ul>
055 */
056@Immutable
057public class AccessTokenResponse extends TokenResponse implements SuccessResponse {
058
059
060        /**
061         * The tokens.
062         */
063        private final Tokens tokens;
064
065
066        /**
067         * Optional custom parameters.
068         */
069        private final Map<String,Object> customParams;
070
071
072        /**
073         * Creates a new access token response.
074         *
075         * @param tokens The tokens. Must not be {@code null}.
076         */
077        public AccessTokenResponse(final Tokens tokens) {
078
079                this(tokens, null);
080        }
081
082
083        /**
084         * Creates a new access token response.
085         *
086         * @param tokens       The tokens. Must not be {@code null}.
087         * @param customParams Optional custom parameters, {@code null} if
088         *                     none.
089         */
090        public AccessTokenResponse(final Tokens tokens,
091                                   final Map<String,Object> customParams) {
092
093                this.tokens = Objects.requireNonNull(tokens);
094                this.customParams = customParams;
095        }
096
097
098        @Override
099        public boolean indicatesSuccess() {
100
101                return true;
102        }
103
104
105        /**
106         * Returns the tokens.
107         *
108         * @return The tokens.
109         */
110        public Tokens getTokens() {
111
112                return tokens;
113        }
114
115
116        /**
117         * Returns the custom parameters.
118         *
119         * @return The custom parameters, as an unmodifiable map, empty map if
120         *         none.
121         */
122        public Map<String,Object> getCustomParameters() {
123
124                if (customParams == null)
125                        return Collections.emptyMap();
126
127                return Collections.unmodifiableMap(customParams);
128        }
129
130
131        @Deprecated
132        public Map<String,Object> getCustomParams() {
133
134                return getCustomParameters();
135        }
136        
137        
138        /**
139         * Returns a JSON object representation of this access token response.
140         *
141         * <p>Example JSON object:
142         *
143         * <pre>
144         * {
145         *   "access_token"  : "SlAV32hkKG",
146         *   "token_type"    : "Bearer",
147         *   "refresh_token" : "8xLOxBtZp8",
148         *   "expires_in"    : 3600
149         * }
150         * </pre>
151         *
152         * @return The JSON object.
153         */
154        public JSONObject toJSONObject() {
155        
156                JSONObject o = tokens.toJSONObject();
157
158                if (customParams != null)
159                        o.putAll(customParams);
160                
161                return o;
162        }
163        
164        
165        @Override
166        public HTTPResponse toHTTPResponse() {
167        
168                HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
169                
170                httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
171                httpResponse.setCacheControl("no-store");
172                httpResponse.setPragma("no-cache");
173                
174                httpResponse.setBody(toJSONObject().toString());
175                
176                return httpResponse;
177        }
178        
179        
180        /**
181         * Parses an access token response from the specified JSON object.
182         *
183         * @param jsonObject The JSON object to parse. Must not be {@code null}.
184         *
185         * @return The access token response.
186         *
187         * @throws ParseException If the JSON object couldn't be parsed to an
188         *                        access token response.
189         */
190        public static AccessTokenResponse parse(final JSONObject jsonObject)
191                throws ParseException {
192                
193                Tokens tokens = Tokens.parse(jsonObject);
194
195                // Determine the custom param names
196                Set<String> customParamNames = new HashSet<>(jsonObject.keySet());
197                customParamNames.removeAll(tokens.getParameterNames());
198
199                Map<String,Object> customParams = null;
200
201                if (! customParamNames.isEmpty()) {
202
203                        customParams = new HashMap<>();
204
205                        for (String name: customParamNames) {
206                                customParams.put(name, jsonObject.get(name));
207                        }
208                }
209                
210                return new AccessTokenResponse(tokens, customParams);
211        }
212        
213        
214        /**
215         * Parses an access token response from the specified HTTP response.
216         *
217         * @param httpResponse The HTTP response. Must not be {@code null}.
218         *
219         * @return The access token response.
220         *
221         * @throws ParseException If the HTTP response couldn't be parsed to an 
222         *                        access token response.
223         */
224        public static AccessTokenResponse parse(final HTTPResponse httpResponse)
225                throws ParseException {
226                
227                httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
228                JSONObject jsonObject = httpResponse.getBodyAsJSONObject();
229                return parse(jsonObject);
230        }
231}