Configure Spring Boot to use Custom Access Token converter - spring

I'm trying to get user information from the access token provided by an Identity Provider. The Identity Provider that I'm using provides it's scope in the form of a string instead of a list because of which the DefaultAccessTokenConverter doesn't work for me. As a result I wish to extend it to a CustomAccessTokenConverter to override it's extractAuthentication() method. I'm using the following in my security config to make Spring use this custom class instead of the default one:
#Configuration
#EnableResourceServer
public class SecurityConfig extends ResourceServerConfigurerAdapter {
#Autowired
private CustomAccessTokenConverter customAccessTokenConverter;
// For validating the incoming access token and fetching user information from it
#Bean
public ResourceServerTokenServices createResourceServerTokenServices() {
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setCheckTokenEndpointUrl(*Introspection URL*);
tokenServices.setClientId(*Client ID*);
tokenServices.setClientSecret(*Client Secret*);
return tokenServices;
}
#Bean
public AccessTokenConverter accessTokenConverter() {
return customAccessTokenConverter;
}
}
But, Spring still uses the DefaultAccessTokenConverter. What am I doing wrong? Please help me out here.
Here is what my CustomAccessTokenConverter class looks like just for reference:
#Component
public class CustomAccessTokenConverter extends DefaultAccessTokenConverter {
#Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
.
.
.
return new OAuth2Authentication(request, user);
}
}
I am using Spring Boot with the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

ResourceTokenServices allows us to use our own AccessTokenConverter.
Simply add the following to your security config:
#Bean
public ResourceServerTokenServices createResourceServerTokenServices() {
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setCheckTokenEndpointUrl(*Introspection URL*);
tokenServices.setClientId(*Client ID*);
tokenServices.setClientSecret(*Client Secret*);
// ADD THE NEXT LINE
tokenServices.setAccessTokenConverter(customAccessTokenConverter);
return tokenServices;
}

Related

Spring cloud zookeeper Config - Set ACL for zookeeper

According to the documentation , I can add authentication information for Zookeeper ACLs by calling the addAuthInfo. But in the Curator Framework bean I don't find the method itself. It throws complilation issue !! .
My POM has
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
How to add zookeeper auth info to Spring Cloud Zookeeper Config. Any working example would help me.
There is a github issue for this problem and it is still in the open status.
As long as this problem is solved by the spring cool team, you can create a custom curator config class and add authentication info to builder method of CuratorFrameworkFactory class:
#BootstrapConfiguration
#ConditionalOnZookeeperEnabled
public class CustomCuratorFrameworkConfig {
#Autowired(required = false)
private EnsembleProvider ensembleProvider;
#Bean
#ConditionalOnMissingBean
public ZookeeperProperties zookeeperProperties() {
return new ZookeeperProperties();
}
#Bean
#ConditionalOnMissingBean
public CuratorFramework curatorFramework(RetryPolicy retryPolicy, ZookeeperProperties properties) throws Exception{
// username and password of the ACL digest scheme
String zkUsername = "user";
String zkPassword = "password";
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();
if (this.ensembleProvider != null) {
builder.ensembleProvider(this.ensembleProvider);
} else {
builder.connectString(properties.getConnectString());
}
builder.retryPolicy(retryPolicy);
String authenticationString = zkUsername + ":" + zkPassword;
builder.authorization("digest", authenticationString.getBytes())
.aclProvider(new ACLProvider() {
#Override
public List<ACL> getDefaultAcl() {
return ZooDefs.Ids.CREATOR_ALL_ACL;
}
#Override
public List<ACL> getAclForPath(String path) {
return ZooDefs.Ids.CREATOR_ALL_ACL;
}
});
CuratorFramework curator = builder.build();
curator.start();
curator.blockUntilConnected(properties.getBlockUntilConnectedWait(), properties.getBlockUntilConnectedUnit());
return curator;
}
#Bean
#ConditionalOnMissingBean
public RetryPolicy exponentialBackoffRetry(ZookeeperProperties properties) {
return new ExponentialBackoffRetry(properties.getBaseSleepTimeMs(), properties.getMaxRetries(), properties.getMaxSleepMs());
}
}
And then continue like this spring document :
You can register configuration classes to run during this phase by annotating them with #BootstrapConfiguration and including them in a comma-separated list that you set as the value of the org.springframework.cloud.bootstrap.BootstrapConfiguration property in the resources/META-INF/spring.factories file
resources/META-INF/spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
my.project.CustomCuratorFrameworkConfig

Spring Data Mongodb WriteConcern working?

I have the following Spring Data MongoDb Repository Java configuration:
#EnableMongoRepositories(basePackages= {"com.example.repositories.mongodb"})
public class MongoConfig extends AbstractMongoConfiguration {
private #Value("${mongo.host}") String mongoHost;
private #Value("${mongo.port}") int mongoPort;
private #Value("${mongo.database}") String mongoDatabase;
#Override
protected String getDatabaseName() {
return mongoDatabase;
}
#Override
public Mongo mongo() throws Exception {
MongoClientOptions options = MongoClientOptions.builder()
.connectionsPerHost(100)
.connectTimeout(120000)
.socketTimeout(120000)
.maxWaitTime(1200000)
.threadsAllowedToBlockForConnectionMultiplier(1500)
.writeConcern(WriteConcern.ACKNOWLEDGED)
.build();
MongoClient client = new MongoClient(new ServerAddress(mongoHost, mongoPort), options);
return client;
}
public #Bean PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
I am trying to figure out if the writeConcern is really turned on due to some jUnits not working when running repeatedly. If I place a breakpoint after the client is created above and inspect the client object I can see its property WriteConcern equals:
{w=null, wTimeout=null ms, fsync=null, journal=null}
Which suggests to me that it was not set to ACKNOWLEDGED.
Am I setting it properly and is there a way to see if the correct concern is set? None of the logger options I tried made it output.
My dependencies are:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>${spring.data.mongodb}</version>
</dependency>

Override Spring-Boot's GsonAutoConfiguration with custom Gson

Is there a way to override the GsonAutoConfiguration in spring-boot?
I would like to add some typeAdapter to the gson instance.
Preferably using java configurations
I've added the following to the application.properties.
spring.http.converters.preferred-json-mapper=gson
and the following class
#Configuration
#ConditionalOnClass(Gson.class)
public class GsonConfig {
#Bean
public Gson gson() {
return new GsonBuilder()
.registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter())
.setPrettyPrinting().create();
}
}
I am also using Jersey in the mix as well.
So I've also have the following code, which also didn't work.
InternalApplication.java
import com.google.gson.GsonBuilder;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import org.immutables.gson.stream.GsonMessageBodyProvider;
import org.immutables.gson.stream.GsonProviderOptionsBuilder;
import org.joda.time.DateTime;
public class InternalApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
classes.add(TestResource.class);
return classes;
}
#Override
public Set<Object> getSingletons() {
final Set<Object> singletons = new HashSet<>();
singletons.add(new GsonMessageBodyProvider(
new GsonProviderOptionsBuilder()
.gson(new GsonBuilder()
.registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter())
.setPrettyPrinting()
.create())
.lenient(true)
.build()
)
);
return singletons;
}
}
Since when does Gson have anything to with Jersey in Spring Boot? It doesn't. What you really want to do is first disable Jackson (which is the default provider). Then you can register your GsonMessageBodyProvider.
Basically all you need to do is exclude the Jackson provider from your Maven/Gradle dependencies, as the Jersey starter pulls it in
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</exclusion>
</exclusions>
</dependency>
And I'm not quite sure why you are using an Application class, as Spring Boot doesn't support that for its auto-configuration. You should be using a ResourceConfig class
#Component
#ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(TestResource.class);
register(new GsonMessageBodyProvider(...));
}
}

Spring Boot console password

I use Spring Boot and I have read that a default should be printed out at log file or console - but there is nothing in my log.
I use putty to connect and the connection is find but I dont know the credentials (password). Is there any hint I can do in order to get it work?
[EDIT]
I also added this to lines to my application.properties file:
security.user.name=user
security.user.password=secret
but with no effect.
Log file screenshot:
These are my dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.smartinnotec.accounting</groupId>
<artifactId>smartinnotec-accounting-frontend</artifactId>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.10.4</version>
</dependency>
</dependencies>
[EDIT]
If I remove the both annotations than a password is printed out at start time.
My problem is, that I need the Beans defined in this class.
Actually I dont know what to do?
Is it possible to enable web security and also to print out the password?
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] restEndpointsToSecure;
#Autowired
private XAuthTokenConfigurer xAuthTokenConfigurer;
static {
restEndpointsToSecure = new String[7];
...
}
#Autowired(required = true)
private UserService userService;
public WebSecurityConfig() {
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
final String[] restEndpointsToSecure = WebSecurityConfig.restEndpointsToSecure;
for (final String endpoint : restEndpointsToSecure) {
http.authorizeRequests().antMatchers("/" + endpoint + "/**").hasRole(UserRoleEnum.USER.toString());
}
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterAfter(csrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
xAuthTokenConfigurer.setDetailsService(userDetailsServiceBean());
final SecurityConfigurer<DefaultSecurityFilterChain, HttpSecurity> securityConfigurerAdapter = xAuthTokenConfigurer;
http.apply(securityConfigurerAdapter);
}
#Override
protected void configure(final AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.userDetailsService(new CustomUserDetailsService(userService));
}
#Bean
public CsrfTokenResponseHeaderBindingFilter csrfTokenResponseHeaderBindingFilter() {
return new CsrfTokenResponseHeaderBindingFilter();
}
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public String toString() {
return "[WebSecurityConfig]";
}
}
If you add 'Spring Security' to your project, all sensitive endpoints exposed over HTTP will be protected. By default ‘basic’ authentication will be used with the username user and a generated password (which is printed on the console when the application starts), just like
Using default security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35
Then you can you this password to login.
But you need to ensure that the org.springframework.boot.autoconfigure.security category is set to log INFO messages, otherwise the default password will not be printed.
Or you can change the password by providing a security.user.name for username and security.user.password for password, then the default password will not get printed in console.
I use putty to connect
I think you are looking for a remote shell connection to actuator endpoints. If so, you should add the following into your dependency tree.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-remote-shell</artifactId>
</dependency>
Spring will print the default remote shell password in the console:
Using default password for shell access: 9b1abe6e-4ec0-4dca-a97a-fed2dadf1837
To override the default username/password, add followings into your application.properties file or yml.
management.shell.auth.simple.user.name=username
management.shell.auth.simple.user.password=password

Making Aspectj work on a Spring servlet bean

I am trying to get an aspectprofiler working on a Jersey servlet registered in a spring project. The aspectprofiler is loaded, but don't notice when methods within the Jersey servlet are run.
#EnableAutoConfiguration
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class App {
public static void main(final String[] args) {
final SpringApplicationBuilder sab = new SpringApplicationBuilder(ConsolidatedCustomerMasterApp.class);
sab.run(args);
}
#Bean
public ServletRegistrationBean jerseyServlet() {
final ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), "/*");
registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyInitialization.class.getName());
return registration;
}
#Bean
public AspectProfiler profiler() {
return new AspectProfiler();
}
}
...
public class JerseyInitialization extends ResourceConfig {
public JerseyInitialization() {
packages("com.example.package");
}
...
package com.example.package;
//imports
#Path("/test")
public class RestService {
#GET
#Path("test")
#Produces(MediaType.TEXT_PLAIN)
public String test() {
return "Something";
}
}
...
#Aspect
public class AspectProfiler {
private static final DefaultApplicationProfiler PROFILER = new DefaultApplicationProfiler(
Arrays.<ProfilerOperator> asList(
new StatsdProfilerOperator(),
new LoggingProfilerOperator())
);
private static final String REST_MATCHER =
"execution(* com.example.package..*.*(..))";
#Around(REST_MATCHER)
public Object around(final ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("test");
return PROFILER.around(joinPoint);
}
}
On top of making the Jersey resource classes Spring #Components (and #ComponentScaning for them), you also need to make the ResourceConfig a Spring #Component also. You can see in the Spring Boot JerseyAutoConfigurer that it autowires the ResourceConfig, which it uses for the ServletContainer registration.
One thing to also note is that it creates its own ServletRegistrationBean
public ServletRegistrationBean jerseyServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(
new ServletContainer(this.config), this.path);
addInitParameters(registration);
registration.setName("jerseyServlet");
return registration;
}
When you declare your own, you are overriding this one. You are not adding any special functionality that is not already provided, so just leave the default. Any Jersey specific configurations can be added in the application.properties file or through code configurations.
As for dependencies, I'll just assume you have all the right dependencies. The following are what I used to test
<!-- all 1.2.7.RELEASE -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
See Also:
spring-boot-sample-jersey - from project samples
§26.2 JAX-RS and Jersey - from Spring Boot docs

Resources