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}