001package com.nimbusds.openid.connect.provider.spi.grants;
002
003
004import net.jcip.annotations.Immutable;
005
006import net.minidev.json.JSONObject;
007import org.checkerframework.checker.nullness.qual.Nullable;
008
009import com.nimbusds.oauth2.sdk.ParseException;
010import com.nimbusds.oauth2.sdk.Scope;
011import com.nimbusds.oauth2.sdk.id.ClientID;
012import com.nimbusds.oauth2.sdk.id.Subject;
013import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
014
015
016/**
017 * Authorisation produced by a {@link GrantHandler grant handler} of assertions
018 * (SAML 2.0 or JWT bearer) issued by a third-party security token service.
019 *
020 * <p>Required authorisation details:
021 *
022 * <ul>
023 *     <li>The subject (end-user).
024 *     <li>The client identifier, must be registered with the Connect2id
025 *         server.
026 *     <li>The authorised scope.
027 * </ul>
028 *
029 * <p>All other parameters are optional or have suitable defaults.
030 */
031@Immutable
032public class ThirdPartyAssertionAuthorization extends SubjectAuthorization {
033
034
035        /**
036         * The authorised client identifier, {@code null} if not specified.
037         */
038        private final ClientID clientID;
039
040
041        /**
042         * Creates a new authorisation for a third-party issued assertion grant
043         * where the client acts on behalf of a user.
044         *
045         * <p>See RFC 7521, section 6.3.
046         *
047         * @param subject  The subject (end-user). Must not be {@code null}.
048         * @param clientID The client identifier. Must be registered with the
049         *                 Connect2id server. Must not be {@code null}.
050         * @param scope    The authorised scope values. Must not be
051         *                 {@code null}.
052         */
053        public ThirdPartyAssertionAuthorization(final Subject subject,
054                                                final ClientID clientID,
055                                                final Scope scope) {
056
057                this(subject, clientID, scope, AccessTokenSpec.DEFAULT, IDTokenSpec.NONE, ClaimsSpec.NONE, null);
058        }
059
060
061        /**
062         * Creates a new authorisation for a third-party issued assertion grant
063         * where the client acts on behalf of a user.
064         *
065         * <p>See RFC 7521, section 6.3.
066         *
067         * @param subject         The subject (end-user). Must not be
068         *                        {@code null}.
069         * @param clientID        The client identifier. Must be registered
070         *                        with the Connect2id server. Must not be
071         *                        {@code null}.
072         * @param scope           The authorised scope values. Must not be
073         *                        {@code null}.
074         * @param accessTokenSpec The access token specification. Must not be
075         *                        {@code null}.
076         * @param idTokenSpec     The ID token specification. Must not be
077         *                        {@code null}.
078         * @param claimsSpec      The OpenID claims specification. Must not be
079         *                        {@code null}.
080         * @param data            Additional data as a JSON object,
081         *                        {@code null} if not specified.
082         */
083        public ThirdPartyAssertionAuthorization(final Subject subject,
084                                                final ClientID clientID,
085                                                final Scope scope,
086                                                final AccessTokenSpec accessTokenSpec,
087                                                final IDTokenSpec idTokenSpec,
088                                                final ClaimsSpec claimsSpec,
089                                                final @Nullable JSONObject data) {
090
091                super(subject, scope, accessTokenSpec, idTokenSpec, claimsSpec, data);
092                if (clientID == null) {
093                        throw new IllegalArgumentException("The client identifier must not be null");
094                }
095                this.clientID = clientID;
096        }
097
098
099        /**
100         * Creates a new authorisation for a third-party issued assertion grant
101         * where the client acts on its own behalf.
102         *
103         * <p>See RFC 7521, section 6.2.
104         *
105         * @param subject The client identifier. Must be registered with the
106         *                Connect2id server. Must not be {@code null}.
107         * @param scope   The authorised scope values. Must not be
108         *                {@code null}.
109         */
110        public ThirdPartyAssertionAuthorization(final ClientID subject,
111                                                final Scope scope) {
112
113                this(new Subject(subject.getValue()), subject, scope, AccessTokenSpec.DEFAULT, IDTokenSpec.NONE, ClaimsSpec.NONE, null);
114        }
115
116
117        /**
118         * Creates a new authorisation for a third-party issued assertion grant
119         * where the client acts on its own behalf.
120         *
121         * <p>See RFC 7521, section 6.2.
122         *
123         * @param subject         The client identifier. Must be registered
124         *                        with the Connect2id server. Must not be
125         *                        {@code null}.
126         * @param scope           The authorised scope values. Must not be
127         *                        {@code null}.
128         * @param accessTokenSpec The access token specification. Must not be
129         *                        {@code null}.
130         * @param data            Additional data as a JSON object,
131         *                        {@code null} if not specified.
132         */
133        public ThirdPartyAssertionAuthorization(final ClientID subject,
134                                                final Scope scope,
135                                                final AccessTokenSpec accessTokenSpec,
136                                                final @Nullable JSONObject data) {
137
138                this(new Subject(subject.getValue()), subject, scope, accessTokenSpec, IDTokenSpec.NONE, ClaimsSpec.NONE, data);
139        }
140
141
142        /**
143         * Returns the authorised client.
144         *
145         * @return The authorised client identifier, {@code null} if not
146         *         specified.
147         */
148        public ClientID getClientID() {
149
150                return clientID;
151        }
152
153
154        @Override
155        public JSONObject toJSONObject() {
156
157                JSONObject o = super.toJSONObject();
158                if (clientID != null) {
159                        o.put("client_id", clientID.getValue());
160                }
161                return o;
162        }
163
164
165        /**
166         * Parses a third-party assertion grant authorisation from the
167         * specified JSON object.
168         *
169         * @param jsonObject The JSON object to parse. Must not be
170         *                   {@code null}.
171         *
172         * @return The authorisation.
173         *
174         * @throws ParseException If parsing failed.
175         */
176        public static ThirdPartyAssertionAuthorization parse(final JSONObject jsonObject)
177                throws ParseException {
178
179                SubjectAuthorization subAuthz = SubjectAuthorization.parse(jsonObject);
180
181                ClientID clientID = null;
182                if (jsonObject.containsKey("client_id")) {
183                        clientID = new ClientID(JSONObjectUtils.getString(jsonObject, "client_id"));
184                }
185
186                return new ThirdPartyAssertionAuthorization(
187                        subAuthz.getSubject(),
188                        clientID,
189                        subAuthz.getScope(),
190                        subAuthz.getAccessTokenSpec(),
191                        subAuthz.getIDTokenSpec(),
192                        subAuthz.getClaimsSpec(),
193                        subAuthz.getData());
194        }
195
196
197        /**
198         * Parses a third-party assertion grant authorisation from the
199         * specified JSON object string.
200         *
201         * @param json The JSON object string to parse. Must not be
202         *             {@code null}.
203         *
204         * @return The authorisation.
205         *
206         * @throws ParseException If parsing failed.
207         */
208        public static ThirdPartyAssertionAuthorization parse(final String json)
209                throws ParseException {
210
211                return parse(JSONObjectUtils.parse(json));
212        }
213}