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