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.token;
019
020
021import com.nimbusds.oauth2.sdk.ParseException;
022import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
023import net.minidev.json.JSONObject;
024
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.Map;
028import java.util.Set;
029
030
031/**
032 * Access and optional refresh token.
033 */
034public class Tokens {
035
036
037        /**
038         * Access token.
039         */
040        private final AccessToken accessToken;
041
042
043        /**
044         * Refresh token, {@code null} if not specified.
045         */
046        private final RefreshToken refreshToken;
047        
048        
049        /**
050         * Optional token metadata, intended for server environments.
051         */
052
053        private final Map<String,Object> metadata = new HashMap<>();
054
055
056        /**
057         * Creates a new tokens instance.
058         *
059         * @param accessToken  The access token. Must not be {@code null}.
060         * @param refreshToken The refresh token. If none {@code null}.
061         */
062        public Tokens(final AccessToken accessToken, final RefreshToken refreshToken) {
063
064                if (accessToken == null)
065                        throw new IllegalArgumentException("The access token must not be null");
066
067                this.accessToken = accessToken;
068
069                this.refreshToken = refreshToken;
070        }
071        
072
073        /**
074         * Returns the access token.
075         *
076         * @return The access token.
077         */
078        public AccessToken getAccessToken() {
079
080                return accessToken;
081        }
082
083
084        /**
085         * Returns the access token as type bearer.
086         *
087         * @return The bearer access token, {@code null} if the type is
088         *         different.
089         */
090        public BearerAccessToken getBearerAccessToken() {
091
092                if (accessToken instanceof BearerAccessToken) {
093                        return (BearerAccessToken) accessToken;
094                }
095                
096                if (AccessTokenType.BEARER.equals(accessToken.getType())) {
097                        // Create from AccessToken with Bearer access token type
098                        return new BearerAccessToken(
099                                accessToken.getValue(),
100                                accessToken.getLifetime(),
101                                accessToken.getScope(),
102                                accessToken.getAuthorizationDetails(),
103                                accessToken.getIssuedTokenType()
104                        );
105                }
106
107                return null;
108        }
109        
110        
111        /**
112         * Returns the access token as type DPoP.
113         *
114         * @return The DPoP access token, {@code null} if the type is
115         *         different.
116         */
117        public DPoPAccessToken getDPoPAccessToken() {
118                
119                if (accessToken instanceof DPoPAccessToken) {
120                        // Cast
121                        return (DPoPAccessToken) accessToken;
122                }
123                
124                if (AccessTokenType.DPOP.equals(accessToken.getType())) {
125                        // Create from AccessToken with DPoP access token type
126                        return new DPoPAccessToken(
127                                accessToken.getValue(),
128                                accessToken.getLifetime(),
129                                accessToken.getScope(),
130                                accessToken.getAuthorizationDetails(),
131                                accessToken.getIssuedTokenType()
132                        );
133                }
134                
135                return null;
136        }
137
138
139        /**
140         * Returns the optional refresh token.
141         *
142         * @return The refresh token, {@code null} if none.
143         */
144        public RefreshToken getRefreshToken() {
145
146                return refreshToken;
147        }
148
149
150        /**
151         * Returns the token parameter names for the included tokens.
152         *
153         * @return The token parameter names.
154         */
155        public Set<String> getParameterNames() {
156
157                // Get the std param names for the access + refresh token
158                Set<String> paramNames = accessToken.getParameterNames();
159
160                if (refreshToken != null)
161                        paramNames.addAll(refreshToken.getParameterNames());
162
163                return Collections.unmodifiableSet(paramNames);
164        }
165        
166        
167        /**
168         * Returns the optional modifiable token metadata. Intended for server
169         * environments.
170         *
171         * @return The token metadata.
172         */
173        public Map<String, Object> getMetadata() {
174
175                return metadata;
176        }
177
178
179        /**
180         * Returns the JSON object representation of this token pair.
181         *
182         * <p>Example JSON object:
183         *
184         * <pre>
185         * {
186         *   "access_token"  : "dZdt8BlltORMTz5U",
187         *   "refresh_token" : "E87zjAoeNXaSoF1U"
188         * }
189         * </pre>
190         *
191         * @return The JSON object representation.
192         */
193        public JSONObject toJSONObject() {
194
195                JSONObject o = accessToken.toJSONObject();
196
197                if (refreshToken != null)
198                        o.putAll(refreshToken.toJSONObject());
199
200                return o;
201        }
202        
203        
204        /**
205         * Casts to OpenID Connect tokens.
206         *
207         * @return The OpenID Connect tokens (including an ID token).
208         */
209        public OIDCTokens toOIDCTokens() {
210                
211                return (OIDCTokens)this;
212        }
213
214
215        @Override
216        public String toString() {
217
218                return toJSONObject().toJSONString();
219        }
220
221
222        /**
223         * Parses an access and optional refresh token from the specified JSON
224         * object.
225         *
226         * @param jsonObject The JSON object to parse. Must not be {@code null}.
227         *
228         * @return The tokens.
229         *
230         * @throws ParseException If the JSON object couldn't be parsed to a
231         *                        tokens instance.
232         */
233        public static Tokens parse(final JSONObject jsonObject)
234                throws ParseException {
235
236                return new Tokens(AccessToken.parse(jsonObject), RefreshToken.parse(jsonObject));
237        }
238}