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