Adding Swagger to Dropwizard application, need to provide instance of SwaggerBundleConfiguration? - swagger

I'm super new to all of these frameworks so please try and bear with me here with what feels like should be a super simple thing.
I'm trying to learn the process of integrating Swagger into an existing Dropwizard application to generate the API documentation, ideally using the Swagger UI interface so that it's interactive for people trying to use/learn it. Specifically, using this bundle: smoketurner/dropwizard-swagger
Before trying to wrestle with the full sized project my employer wants it integrated with, I tried adding it into the standard Dropwizard example application, thinking that should be a hassle-free jumping off point. After following the instructions on the github page for the bundle, I'm hit by the following error:
Test set: com.example.helloworld.IntegrationTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.003 s <<< FAILURE! - in com.example.helloworld.IntegrationTest
com.example.helloworld.IntegrationTest Time elapsed: 2.003 s <<< ERROR!
java.lang.IllegalStateException: You need to provide an instance of SwaggerBundleConfiguration
What am I missing?
Below are the Configuration and Application files in question, with the additions made as per the github bundle instructions.
HelloWorldConfiguration:
package com.example.helloworld;
import com.example.helloworld.core.Template;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.Map;
public class HelloWorldConfiguration extends Configuration {
#NotEmpty
private String template;
#NotEmpty
private String defaultName = "Stranger";
#JsonProperty("swagger")
public SwaggerBundleConfiguration swaggerBundleConfiguration;
#Valid
#NotNull
private DataSourceFactory database = new DataSourceFactory();
#NotNull
private Map<String, Map<String, String>> viewRendererConfiguration = Collections.emptyMap();
#JsonProperty
public String getTemplate() {
return template;
}
#JsonProperty
public void setTemplate(String template) {
this.template = template;
}
#JsonProperty
public String getDefaultName() {
return defaultName;
}
#JsonProperty
public void setDefaultName(String defaultName) {
this.defaultName = defaultName;
}
public Template buildTemplate() {
return new Template(template, defaultName);
}
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
#JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.database = dataSourceFactory;
}
#JsonProperty("viewRendererConfiguration")
public Map<String, Map<String, String>> getViewRendererConfiguration() {
return viewRendererConfiguration;
}
#JsonProperty("viewRendererConfiguration")
public void setViewRendererConfiguration(Map<String, Map<String, String>> viewRendererConfiguration) {
final ImmutableMap.Builder<String, Map<String, String>> builder = ImmutableMap.builder();
for (Map.Entry<String, Map<String, String>> entry : viewRendererConfiguration.entrySet()) {
builder.put(entry.getKey(), ImmutableMap.copyOf(entry.getValue()));
}
this.viewRendererConfiguration = builder.build();
}
}
HelloWorldApplication:
package com.example.helloworld;
import com.example.helloworld.auth.ExampleAuthenticator;
import com.example.helloworld.auth.ExampleAuthorizer;
import com.example.helloworld.cli.RenderCommand;
import com.example.helloworld.core.Person;
import com.example.helloworld.core.Template;
import com.example.helloworld.core.User;
import com.example.helloworld.db.PersonDAO;
import com.example.helloworld.filter.DateRequiredFeature;
import com.example.helloworld.health.TemplateHealthCheck;
import com.example.helloworld.resources.FilteredResource;
import com.example.helloworld.resources.HelloWorldResource;
import com.example.helloworld.resources.PeopleResource;
import com.example.helloworld.resources.PersonResource;
import com.example.helloworld.resources.ProtectedResource;
import com.example.helloworld.resources.ViewResource;
import com.example.helloworld.tasks.EchoTask;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.configuration.EnvironmentVariableSubstitutor;
import io.dropwizard.configuration.SubstitutingSourceProvider;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.hibernate.HibernateBundle;
import io.dropwizard.migrations.MigrationsBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.dropwizard.views.ViewBundle;
import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import java.util.Map;
public class HelloWorldApplication extends Application<HelloWorldConfiguration> {
public static void main(String[] args) throws Exception {
new HelloWorldApplication().run(args);
}
private final HibernateBundle<HelloWorldConfiguration> hibernateBundle =
new HibernateBundle<HelloWorldConfiguration>(Person.class) {
#Override
public DataSourceFactory getDataSourceFactory(HelloWorldConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Override
public String getName() {
return "hello-world";
}
#Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
// Enable variable substitution with environment variables
bootstrap.setConfigurationSourceProvider(
new SubstitutingSourceProvider(
bootstrap.getConfigurationSourceProvider(),
new EnvironmentVariableSubstitutor(false)
)
);
bootstrap.addCommand(new RenderCommand());
bootstrap.addBundle(new AssetsBundle());
bootstrap.addBundle(new MigrationsBundle<HelloWorldConfiguration>() {
#Override
public DataSourceFactory getDataSourceFactory(HelloWorldConfiguration configuration) {
return configuration.getDataSourceFactory();
}
});
bootstrap.addBundle(hibernateBundle);
bootstrap.addBundle(new ViewBundle<HelloWorldConfiguration>() {
#Override
public Map<String, Map<String, String>> getViewConfiguration(HelloWorldConfiguration configuration) {
return configuration.getViewRendererConfiguration();
}
});
bootstrap.addBundle(new SwaggerBundle<HelloWorldConfiguration>() {
#Override
protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(HelloWorldConfiguration configuration) {
return configuration.swaggerBundleConfiguration;
}
});
}
#Override
public void run(HelloWorldConfiguration configuration, Environment environment) {
final PersonDAO dao = new PersonDAO(hibernateBundle.getSessionFactory());
final Template template = configuration.buildTemplate();
environment.healthChecks().register("template", new TemplateHealthCheck(template));
environment.admin().addTask(new EchoTask());
environment.jersey().register(DateRequiredFeature.class);
environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new ExampleAuthenticator())
.setAuthorizer(new ExampleAuthorizer())
.setRealm("SUPER SECRET STUFF")
.buildAuthFilter()));
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
environment.jersey().register(RolesAllowedDynamicFeature.class);
environment.jersey().register(new HelloWorldResource(template));
environment.jersey().register(new ViewResource());
environment.jersey().register(new ProtectedResource());
environment.jersey().register(new PeopleResource(dao));
environment.jersey().register(new PersonResource(dao));
environment.jersey().register(new FilteredResource());
}
}

For anyone else trying to learn this and struggling, the issue was that the included test suite in the sample application has its own YML file, test-example.yml that you also need to add the swagger properties into. This will allow the tests to pass and everything should go smoothly from there.
Added properties to test-example.yml:
swagger:
resourcePackage: com.example.helloworld.resources

Related

including keyclocak group IDs in token

I am new to keyclocak. I have group assignments for users, and I was able to enable a group mapper, which puts groups (names only) in the token returned to a client. In my app, I need to associate data with groups, so I'd like for a way to add group IDs to the token.
Is there a way I can add the group ID to the token? Or, can my app query for group ids/names without having to have admin credentials on keycloak?
You can use a custom protocol mapper:
package org.sample;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.keycloak.models.ClientSessionContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper;
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
import org.keycloak.protocol.oidc.mappers.UserInfoTokenMapper;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.IDToken;
public class GroupIdProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
public static final String PROVIDER_ID = "group-id-protocol-mapper";
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
static {
OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, GroupIdProtocolMapper.class);
}
#Override
public String getId() {
return PROVIDER_ID;
}
#Override
public String getDisplayCategory() {
return TOKEN_MAPPER_CATEGORY;
}
#Override
public String getDisplayType() {
return "Group Id";
}
#Override
public String getHelpText() {
return "Map user group id to a token claim.";
}
#Override
public List<ProviderConfigProperty> getConfigProperties() {
return configProperties;
}
#Override
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession keycloakSession,
ClientSessionContext clientSessionCtx) {
List<String> groups = (List)userSession.getUser().getGroupsStream().map((g) -> {
return g.getId();
}).collect(Collectors.toList());
String protocolClaim = (String)mappingModel.getConfig().get("claim.name");
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, groups);
}
}

Whitelisting application properties in Spring Cloud Data Flow

When I create a custom app for SCDF I can, according to the reference define relevant properties that are visible through the dashboard when creating a new stream/task. I created a spring-configuration-metadata-whitelist.properties file like this:
configuration-properties.classes=com.example.MySourceProperties
configuration-properties.names=my.prop1,my.prop2
When I create a new stream definition through the dashboard all properties defined in com.example.MySourceProperties are displayed in the properties dialog, but my.prop1 and my.prop2 are not. Both properties aren't optional and must always be set by the user. How can I include them in the properties dialog?
This tells it which class to pull these properties from Task1 properties class
That we can use with "#EnableConfigurationProperties(Task1Properties.class) declaration
configuration-properties.classes=com.shifthunter.tasks.Task1Properties
Task1Properties.java
package com.shifthunter.tasks;
import org.springframework.boot.context.properties.ConfigurationProperties;
#ConfigurationProperties("pulldata-task")
public class Task1Properties {
/**
* The path to get the source doc from
*/
private String sourceFilePath;
/**
* The path to put the destination doc
*/
private String destinationFilePath;
/**
* Property to drive the exit code
*/
private String controlMessage;
public String getSourceFilePath() {
return sourceFilePath;
}
public void setSourceFilePath(String sourceFilePath) {
this.sourceFilePath = sourceFilePath;
}
public String getDestinationFilePath() {
return destinationFilePath;
}
public void setDestinationFilePath(String destinationFilePath) {
this.destinationFilePath = destinationFilePath;
}
public String getControlMessage() {
return controlMessage;
}
public void setControlMessage(String controlMessage) {
this.controlMessage = controlMessage;
}
}
ShiftHunterTaskPullDataApp.java
package com.shifthunter.tasks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#EnableTask
#EnableConfigurationProperties(Task1Properties.class)
#SpringBootApplication
public class ShiftHunterTaskPullDataApp {
public static void main(String[] args) {
SpringApplication.run(ShiftHunterTaskPullDataApp.class, args);
}
#Bean
public Task1 task1() {
return new Task1();
}
public class Task1 implements CommandLineRunner {
#Autowired
private Task1Properties config;
#Override
public void run(String... strings) throws Exception {
System.out.println("source: " + config.getSourceFilePath());
System.out.println("destination: " + config.getDestinationFilePath());
System.out.println("control message: " + config.getControlMessage());
if(config.getControlMessage().equals("fail")) {
System.out.println("throwing an exception ...");
throw new Exception("I'm ANGRY");
}
System.out.println("pulldata-task complete!");
}
}
}
Sream Dataflow task-pull-data
app register --name task-pull-data --type task --uri maven://com.shifthunter.tasks:shifthunter-task-pulldata:jar:0.0.1-SNAPSHOT
task-pull-data - Details

spring boot spring rabbit: How to create a rabbit template to send a message within a listener

I have a simple listener that is receiving messages from Rabbitmq. I would like to modify the message and publish it to a new exchange/queue. I have been unable to get a rabbit template to work within a listener. Any help would be appreciated. My code is below, when I tried to autowire the template I get
Caused by: java.lang.NullPointerException: null
at com.example.Consumer.onMessage(Consumer.java:27) ~[classes!/:0.0.1-SNAPSHOT]
Classes:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RabbittestApplication {
public static void main(String[] args) {
SpringApplication.run(RabbittestApplication.class, args);
}
}
package com.example;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration
public class RabbitConfig {
private static final String SIMPLE_MESSAGE_QUEUE = "qDLX1.dlx";
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("RabbitErl19");
connectionFactory.setUsername("gregg");
connectionFactory.setPassword("gregg");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("dlxtest");
return connectionFactory;
}
#Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
return template;
}
#Bean
public SimpleMessageListenerContainer listenerContainer() {
SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer();
listenerContainer.setConnectionFactory(connectionFactory());
listenerContainer.setQueueNames(SIMPLE_MESSAGE_QUEUE);
listenerContainer.setMessageListener(new Consumer());
listenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
return listenerContainer;
}
}
package com.example;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Consumer implements MessageListener {
#Autowired
private RabbitTemplate rabbitTemplate;
#Override
public void onMessage(Message message) {
System.out.println("Body: "+new String(message.getBody()));
System.out.println();
message.getMessageProperties().setExpiration("5000");
rabbitTemplate.send("xDLX1.delay", "xq1.retry", message);
}
}
Here is your code:
listenerContainer.setMessageListener(new Consumer());
As you see it is absolutely normal that #Autowired doesn't work. Just because you have bypassed dependency injection.
Since your Consumer is marked with #Component you can simply inject it into that SimpleMessageListenerContainer bean definition:
#Bean
public SimpleMessageListenerContainer listenerContainer(Consumer consumer)
Thanks that did it, I changed my code to what is below and it worked. Your help is much appreciated!
#Autowired
private Consumer consumer;
#Bean
public SimpleMessageListenerContainer listenerContainer() {
SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer();
listenerContainer.setConnectionFactory(connectionFactory());
listenerContainer.setQueueNames(SIMPLE_MESSAGE_QUEUE);
listenerContainer.setMessageListener(consumer);
listenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
return listenerContainer;
}

Spring MongoDB mapping OAuth2Authentication

I'm writing my own implementation of TokenStore (org.springframework.security.oauth2.provider.token.TokenStore) using MongoDB. There seems to be some problem with converting/mapping of the object in the database back to Java object.
Anyone have a clue how I could solve this?
org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate org.springframework.security.authentication.UsernamePasswordAuthenticationToken using constructor NO_CONSTRUCTOR with arguments
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:64) ~[spring-data-commons-1.11.0.RELEASE.jar:na]
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:83) ~[spring-data-commons-1.11.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:251) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:231) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1185) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$200(MappingMongoConverter.java:78) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
You need to create a converter and register it as Spring Mongo doesn't do this for you.
Create a converter
import com.erranda.abraham.entity.Person;
import com.mongodb.DBObject;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import java.util.*;
/**
* #version 1.0
* #author: Iain Porter
* #since 23/05/2013
*/
//Hackery to deserialize back into an OAuth2Authentication Object made necessary because Spring Mongo can't map clientAuthentication to authorizationRequest
#ReadingConverter
#SuppressWarnings("rawtypes")
public class OAuth2AuthenticationReadConverter implements Converter<DBObject, OAuth2Authentication> {
#Override
#SuppressWarnings("unchecked")
public OAuth2Authentication convert(DBObject source) {
System.out.println(source);
DBObject storedRequest = (DBObject)source.get("storedRequest");
OAuth2Request oAuth2Request = new OAuth2Request((Map<String, String>)storedRequest.get("requestParameters"),
(String)storedRequest.get("clientId"), null, true, new HashSet((List)storedRequest.get("scope")),
null, null, null, null);
DBObject userAuthorization = (DBObject)source.get("userAuthentication");
Object principal = getPrincipalObject(userAuthorization.get("principal"));
Authentication userAuthentication = new UsernamePasswordAuthenticationToken(principal,
(String)userAuthorization.get("credentials"), getAuthorities((List) userAuthorization.get("authorities")));
OAuth2Authentication authentication = new OAuth2Authentication(oAuth2Request,
userAuthentication );
return authentication;
}
private Object getPrincipalObject(Object principal) {
if(principal instanceof DBObject) {
DBObject principalDBObject = (DBObject)principal;
Person user = new Person (principalDBObject);
return user;
} else {
return principal;
}
}
private Collection<GrantedAuthority> getAuthorities(List<Map<String, String>> authorities) {
Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>(authorities.size());
for(Map<String, String> authority : authorities) {
grantedAuthorities.add(new SimpleGrantedAuthority(authority.get("role")));
}
return grantedAuthorities;
}
}
Then you need to register converter along side your mongodb configuration
import com.erranda.abraham.api.security.OAuth2AuthenticationReadConverter;
import com.mongodb.Mongo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
#Configuration
public class MongoDbConfiguration extends AbstractMongoConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(MongoDbConfiguration.class);
private static final String MONGO_DB_SERVER = "mongo.db.server";
private static final String MONGO_DB_PORT = "mongo.db.port";
private static final String MONGO_DB_NAME = "mongo.db.name";
private static final String MONGO_DB_LOGON = "mongo.db.logon";
private static final String MONGO_DB_PASSWORD = "mongo.db.password";
private static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";
#Autowired
private ApplicationContext applicationContext;
#Value("${" + MONGO_DB_SERVER + "}")
private String mongoServer;
#Value("${" + MONGO_DB_PORT + "}")
private int mongoPort;
#Value("${" + MONGO_DB_NAME + "}")
private String mongoDBName;
#Value("${" + MONGO_DB_LOGON + "}")
private String mongoDbLogin;
#Value("${" + MONGO_DB_PASSWORD + "}")
private String mongoDbPassword;
#Override
protected String getDatabaseName() {
return mongoDBName;
}
#Override
#Bean
public Mongo mongo() throws Exception {
return new Mongo(mongoServer, mongoPort);
}
#Override
#Bean
public MongoTemplate mongoTemplate() throws Exception {
if (!StringUtils.isEmpty(mongoDbLogin)) {
LOG.info("Configuring mongoTemplate with credentials.");
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo(), mongoDBName, new UserCredentials(mongoDbLogin, mongoDbPassword));
return new MongoTemplate(mongoDbFactory, mappingMongoConverter());
} else {
LOG.info("Configuring mongoTemplate without credentials.");
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo(), mongoDBName);
return new MongoTemplate(mongoDbFactory, mappingMongoConverter());
}
}
#Override
#Bean
public CustomConversions customConversions() {
List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
OAuth2AuthenticationReadConverter converter = new OAuth2AuthenticationReadConverter();
converterList.add(converter);
return new CustomConversions(converterList);
}
private String getContextProperty(final String propertyKey) {
return applicationContext.getEnvironment().getProperty(propertyKey);
}
}
Don't forget to mark as correct if it works for you.
Based on https://github.com/iainporter/oauth2-provider

JedisDataException when upgrading spring-session from 1.0.0.RC1 to 1.0.0.RELEASE

We are trying to upgrade from RC1 to RELEASE, but we are now getting the following exception:
Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR unknown command 'CONFIG'
at redis.clients.jedis.Protocol.processError(Protocol.java:100) ~[Protocol.class:na]
at redis.clients.jedis.Protocol.process(Protocol.java:118) ~[Protocol.class:na]
at redis.clients.jedis.Protocol.read(Protocol.java:187) ~[Protocol.class:na]
at redis.clients.jedis.Connection.getBinaryMultiBulkReply(Connection.java:212) ~[Connection.class:na]
at redis.clients.jedis.Connection.getMultiBulkReply(Connection.java:205) ~[Connection.class:na]
at redis.clients.jedis.Jedis.configGet(Jedis.java:2701) ~[Jedis.class:na]
at org.springframework.data.redis.connection.jedis.JedisConnection.getConfig(JedisConnection.java:531) ~[JedisConnection.class:1.3.0.RELEASE]
... 29 common frames omitted
Here is my SessionConfig:
#EnableRedisHttpSession
public class SessionConfig {
private static final int SESSION_EXPIRATION_TIME = 28800;
#Autowired
private Environment env;
#Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(env.getProperty("reddis.host"));
jedisConnectionFactory.setPort(env.getProperty("reddis.port", Integer.class));
return jedisConnectionFactory;
}
#Bean
public HttpSessionStrategy httpSessionStrategy() {
return new HeaderHttpSessionStrategy();
}
#Bean
public RedisOperationsSessionRepository sessionRepository() {
RedisOperationsSessionRepository redisOperationsSessionRepository = new RedisOperationsSessionRepository(connectionFactory());
redisOperationsSessionRepository.setDefaultMaxInactiveInterval(SESSION_EXPIRATION_TIME);
return redisOperationsSessionRepository;
}
}
We are using redis 2.8.6 with AWS ElastiCache, spring framework 4.1.4, spring-data-redis 1.3.0.RELEASE and jedis client 2.4.1.
Any idea why we are facing this issue?
Thanks!
You are experiencing this bug. In short, Spring Session is attempting to configure Redis for you and AWS disables configuring Redis (for security reasons).
To get around this, you can replace the EnableRedisHttpSession with an #Import(Issue124Config.class) and following configuration:
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.session.ExpiringSession;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.SessionMessageListener;
import org.springframework.session.web.http.HttpSessionStrategy;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.util.ClassUtils;
#Configuration
public class Issue124Config {
#Value("${spring.session.maxInactive ?: 1800}")
private Integer maxInactiveIntervalInSeconds;
private HttpSessionStrategy httpSessionStrategy;
#Bean
public RedisTemplate<String,ExpiringSession> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(connectionFactory);
return template;
}
#Bean
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, ExpiringSession> sessionRedisTemplate) {
RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
sessionRepository.setDefaultMaxInactiveInterval(maxInactiveIntervalInSeconds);
return sessionRepository;
}
#Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
if(httpSessionStrategy != null) {
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
}
return sessionRepositoryFilter;
}
#Autowired(required = false)
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
this.httpSessionStrategy = httpSessionStrategy;
}
}

Resources