Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;


/**
* Jackson Mixin class helps in serialize/deserialize
* {@link org.springframework.security.oauth2.core.AuthorizationGrantType}.
*
* @author Junlin Zhou
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class AuthorizationGrantTypeMixin {

@JsonGetter("value")
abstract long getValue();

@JsonCreator
public AuthorizationGrantTypeMixin(@JsonProperty("value") String value) {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

/**
* Jackson Mixin class helps in serialize/deserialize
* {@link org.springframework.security.oauth2.core.ClientAuthenticationMethod}.
*
* @author Junlin Zhou
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class ClientAuthenticationMethodMixin {

@JsonGetter("value")
abstract long getValue();

@JsonCreator
public ClientAuthenticationMethodMixin(@JsonProperty("value") String value) {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;

import java.io.IOException;
import java.util.Map;

/**
* Deserializer used for deserializing {@link ClientSettings} from JSON.
*
* @author Junlin Zhou
*/
public class ClientSettingsDeserializer extends JsonDeserializer<ClientSettings> {

@Override
public ClientSettings deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
ObjectMapper mapper = (ObjectMapper) p.getCodec();
JsonNode root = mapper.readTree(p);
Map<String, Object> settings = JsonNodeUtils
.findValue(root, "settings", JsonNodeUtils.STRING_OBJECT_MAP, mapper);
return ClientSettings.withSettings(settings).build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

/**
* Jackson Mixin class helps in serialize/deserialize
* {@link org.springframework.security.oauth2.server.authorization.config.ClientSettings}.
*
* @author Junlin Zhou
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonDeserialize(using = ClientSettingsDeserializer.class)
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class ClientSettingsMixin {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

/**
* Jackson Mixin class helps in serialize/deserialize
* {@link java.time.Instant}.
*
* @author Junlin Zhou
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE,
creatorVisibility = JsonAutoDetect.Visibility.NONE)
abstract class InstantMixin {

@JsonCreator
static void ofSeconds(@JsonProperty("seconds") long seconds, @JsonProperty("nano") long nanoAdjustment) {
}

@JsonGetter("seconds")
abstract long getSeconds();

@JsonGetter("nano")
abstract int getNano();

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
Expand All @@ -24,8 +25,14 @@
import com.fasterxml.jackson.databind.module.SimpleModule;

import org.springframework.security.jackson2.SecurityJackson2Modules;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;

/**
* Jackson {@code Module} for {@code spring-authorization-server}, that registers the
Expand Down Expand Up @@ -75,7 +82,14 @@ public void setupModule(SetupContext context) {
context.setMixInAnnotations(LinkedHashSet.class, HashSetMixin.class);
context.setMixInAnnotations(OAuth2AuthorizationRequest.class, OAuth2AuthorizationRequestMixin.class);
context.setMixInAnnotations(Duration.class, DurationMixin.class);
context.setMixInAnnotations(Instant.class, InstantMixin.class);
context.setMixInAnnotations(SignatureAlgorithm.class, SignatureAlgorithmMixin.class);
context.setMixInAnnotations(OAuth2ClientAuthenticationToken.class, OAuth2ClientAuthenticationTokenMixin.class);
context.setMixInAnnotations(RegisteredClient.class, RegisteredClientMixin.class);
context.setMixInAnnotations(AuthorizationGrantType.class, AuthorizationGrantTypeMixin.class);
context.setMixInAnnotations(ClientAuthenticationMethod.class, ClientAuthenticationMethodMixin.class);
context.setMixInAnnotations(TokenSettings.class, TokenSettingsMixin.class);
context.setMixInAnnotations(ClientSettings.class, ClientSettingsMixin.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.StdConverter;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;

import java.io.IOException;
import java.util.Map;

/**
* Deserializer used for deserializing {@link OAuth2ClientAuthenticationToken} from JSON.
*
* @author Junlin Zhou
*/
public class OAuth2ClientAuthenticationTokenDeserializer extends JsonDeserializer<OAuth2ClientAuthenticationToken> {

private static final StdConverter<JsonNode, ClientAuthenticationMethod> CLIENT_AUTHENTICATION_METHOD_CONVERTER =
new StdConverters.ClientAuthenticationMethodConverter();

private static final TypeReference<RegisteredClient> REGISTERED_CLIENT_TYPE_REFERENCE =
new TypeReference<RegisteredClient>() {
};

/**
* {@inheritDoc}
*/
@Override
public OAuth2ClientAuthenticationToken deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
ObjectMapper mapper = (ObjectMapper) p.getCodec();
JsonNode root = mapper.readTree(p);

Object credentials = JsonNodeUtils.findStringValue(root, "credentials");

ClientAuthenticationMethod clientAuthenticationMethod = CLIENT_AUTHENTICATION_METHOD_CONVERTER
.convert(JsonNodeUtils.findObjectNode(root, "clientAuthenticationMethod"));

boolean authenticated = findBooleanValue(root, "authenticated");

if (authenticated) {
RegisteredClient registeredClient = JsonNodeUtils
.findValue(root, "registeredClient", REGISTERED_CLIENT_TYPE_REFERENCE, mapper);
return new OAuth2ClientAuthenticationToken(registeredClient, clientAuthenticationMethod, credentials);
} else {
String clientId = JsonNodeUtils.findStringValue(root, "clientId");
Map<String, Object> additionalParameters = JsonNodeUtils
.findValue(root, "additionalParameters", JsonNodeUtils.STRING_OBJECT_MAP, mapper);
return new OAuth2ClientAuthenticationToken(clientId, clientAuthenticationMethod, credentials,
additionalParameters);
}
}

private boolean findBooleanValue(JsonNode jsonNode, String fieldName) {
if (jsonNode == null) {
return false;
}
JsonNode value = jsonNode.findValue(fieldName);
return (value != null && value.asBoolean());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

/**
* Jackson Mixin class helps in serialize/deserialize
* {@link org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken}.
*
* @author Junlin Zhou
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonDeserialize(using = OAuth2ClientAuthenticationTokenDeserializer.class)
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class OAuth2ClientAuthenticationTokenMixin {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;

import java.io.IOException;
import java.time.Instant;
import java.util.Set;

/**
* Deserializer used for deserializing {@link RegisteredClient} from JSON.
*
* @author Junlin Zhou
*/
public class RegisteredClientDeserializer extends JsonDeserializer<RegisteredClient> {

private static final TypeReference<Set<AuthorizationGrantType>> AUTHORIZATION_GRANT_TYPE_SET =
new TypeReference<Set<AuthorizationGrantType>>() {
};

private static final TypeReference<Set<ClientAuthenticationMethod>> CLIENT_AUTHENTICATION_METHOD_SET =
new TypeReference<Set<ClientAuthenticationMethod>>() {
};

private static final TypeReference<ClientSettings> CLIENT_SETTINGS_TYPE_REFERENCE =
new TypeReference<ClientSettings>() {
};

private static final TypeReference<TokenSettings> TOKEN_SETTINGS_TYPE_REFERENCE =
new TypeReference<TokenSettings>() {
};

private static final TypeReference<Instant> INSTANT_TYPE_REFERENCE = new TypeReference<Instant>() {
};

/**
* {@inheritDoc}
*/
@Override
public RegisteredClient deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
ObjectMapper mapper = (ObjectMapper) p.getCodec();
JsonNode root = mapper.readTree(p);
return deserialize(root, mapper);
}

private RegisteredClient deserialize(JsonNode root, ObjectMapper mapper) {
String id = JsonNodeUtils.findStringValue(root, "id");
String clientId = JsonNodeUtils.findStringValue(root, "clientId");
String clientSecret = JsonNodeUtils.findStringValue(root, "clientSecret");
String clientName = JsonNodeUtils.findStringValue(root, "clientName");

Instant clientIdIssuedAt = JsonNodeUtils
.findValue(root, "clientIdIssuedAt", INSTANT_TYPE_REFERENCE, mapper);

Instant clientSecretExpiresAt = JsonNodeUtils
.findValue(root, "clientSecretExpiresAtNode", INSTANT_TYPE_REFERENCE, mapper);

Set<AuthorizationGrantType> grantTypes = JsonNodeUtils
.findValue(root, "authorizationGrantTypes", AUTHORIZATION_GRANT_TYPE_SET, mapper);
Set<ClientAuthenticationMethod> clientAuthenticationMethods = JsonNodeUtils
.findValue(root, "clientAuthenticationMethods", CLIENT_AUTHENTICATION_METHOD_SET, mapper);
Set<String> redirectUris = JsonNodeUtils
.findValue(root, "redirectUris", JsonNodeUtils.STRING_SET, mapper);
Set<String> scopes = JsonNodeUtils.findValue(root, "scopes", JsonNodeUtils.STRING_SET, mapper);

ClientSettings clientSettings = JsonNodeUtils
.findValue(root, "clientSettings", CLIENT_SETTINGS_TYPE_REFERENCE, mapper);
TokenSettings tokenSettings = JsonNodeUtils
.findValue(root, "tokenSettings", TOKEN_SETTINGS_TYPE_REFERENCE, mapper);

return RegisteredClient
.withId(id)
.clientId(clientId)
.clientIdIssuedAt(clientIdIssuedAt)
.clientSecret(clientSecret)
.clientSecretExpiresAt(clientSecretExpiresAt)
.clientName(clientName)
.clientAuthenticationMethods(consumer -> consumer.addAll(clientAuthenticationMethods))
.authorizationGrantTypes(consumer -> consumer.addAll(grantTypes))
.redirectUris(consumer -> consumer.addAll(redirectUris))
.scopes(consumer -> consumer.addAll(scopes))
.clientSettings(clientSettings)
.tokenSettings(tokenSettings)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.springframework.security.oauth2.server.authorization.jackson2;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

/**
* Jackson Mixin class helps in serialize/deserialize
* {@link org.springframework.security.oauth2.server.authorization.client.RegisteredClient}.
*
* @author Junlin Zhou
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonDeserialize(using = RegisteredClientDeserializer.class)
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class RegisteredClientMixin {
}
Loading