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