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.openid.connect.sdk.token;
019
020
021import java.util.Set;
022
023import com.nimbusds.jwt.JWT;
024
025import net.jcip.annotations.Immutable;
026
027import net.minidev.json.JSONObject;
028
029import com.nimbusds.jwt.JWTParser;
030
031import com.nimbusds.oauth2.sdk.ParseException;
032import com.nimbusds.oauth2.sdk.token.AccessToken;
033import com.nimbusds.oauth2.sdk.token.RefreshToken;
034import com.nimbusds.oauth2.sdk.token.Tokens;
035import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
036
037
038/**
039 * ID token, access token and optional refresh token.
040 */
041@Immutable
042public final class OIDCTokens extends Tokens {
043
044
045        /**
046         * The ID Token serialised to a JWT. If not specified then the
047         * serialised variant.
048         */
049        private final JWT idToken;
050
051
052        /**
053         * The ID Token as raw string (for more efficient serialisation). If
054         * not specified then the unserialised variant.
055         */
056        private final String idTokenString;
057
058
059        /**
060         * Creates a new OpenID Connect tokens instance.
061         *
062         * @param idToken      The ID token. Must not be {@code null}.
063         * @param accessToken  The access token. Must not be {@code null}.
064         * @param refreshToken The refresh token. If none {@code null}.
065         */
066        public OIDCTokens(final JWT idToken, final AccessToken accessToken, final RefreshToken refreshToken) {
067
068                super(accessToken, refreshToken);
069
070                if (idToken == null) {
071                        throw new IllegalArgumentException("The ID token must not be null");
072                }
073
074                this.idToken = idToken;
075                idTokenString = null;
076        }
077
078
079        /**
080         * Creates a new OpenID Connect tokens instance.
081         *
082         * @param idTokenString The ID token string. Must not be {@code null}.
083         * @param accessToken   The access token. Must not be {@code null}.
084         * @param refreshToken  The refresh token. If none {@code null}.
085         */
086        public OIDCTokens(final String idTokenString, final AccessToken accessToken, final RefreshToken refreshToken) {
087
088                super(accessToken, refreshToken);
089
090                if (idTokenString == null) {
091                        throw new IllegalArgumentException("The ID token string must not be null");
092                }
093
094                this.idTokenString = idTokenString;
095                idToken = null;
096        }
097
098
099        /**
100         * Gets the ID token.
101         *
102         * @return The ID token, {@code null} if none or if parsing to a JWT
103         *         failed.
104         */
105        public JWT getIDToken() {
106
107                if (idToken != null)
108                        return idToken;
109
110                if (idTokenString != null) {
111
112                        try {
113                                return JWTParser.parse(idTokenString);
114
115                        } catch (java.text.ParseException e) {
116
117                                return null;
118                        }
119                }
120
121                return null;
122        }
123
124
125        /**
126         * Gets the ID token string.
127         *
128         * @return The ID token string, {@code null} if none or if
129         *         serialisation to a string failed.
130         */
131        public String getIDTokenString() {
132
133                if (idTokenString != null)
134                        return idTokenString;
135
136                if (idToken != null) {
137
138                        // Reproduce originally parsed string if any
139                        if (idToken.getParsedString() != null)
140                                return idToken.getParsedString();
141
142                        try {
143                                return idToken.serialize();
144
145                        } catch(IllegalStateException e) {
146
147                                return null;
148                        }
149                }
150
151                return null;
152        }
153
154
155        @Override
156        public Set<String> getParameterNames() {
157
158                Set<String> paramNames = super.getParameterNames();
159                paramNames.add("id_token");
160                return paramNames;
161        }
162
163
164        @Override
165        public JSONObject toJSONObject() {
166
167                JSONObject o = super.toJSONObject();
168                o.put("id_token", getIDTokenString());
169                return o;
170        }
171
172
173        /**
174         * Parses an OpenID Connect tokens instance from the specified JSON
175         * object.
176         *
177         * @param jsonObject The JSON object to parse. Must not be {@code null}.
178         *
179         * @return The OpenID Connect tokens.
180         *
181         * @throws ParseException If the JSON object couldn't be parsed to an
182         *                        OpenID Connect tokens instance.
183         */
184        public static OIDCTokens parse(final JSONObject jsonObject)
185                throws ParseException {
186
187                JWT idToken;
188
189                try {
190                        idToken = JWTParser.parse(JSONObjectUtils.getString(jsonObject, "id_token"));
191
192                } catch (java.text.ParseException e) {
193
194                        throw new ParseException("Couldn't parse ID token: " + e.getMessage(), e);
195                }
196
197                return new OIDCTokens(idToken, AccessToken.parse(jsonObject), RefreshToken.parse(jsonObject));
198        }
199}