spring boot 3 - digest authentication not working - spring

I am not able to create a simple rest API with digest authentication with spring boot 3. It was working with version 2, but with a different configuration, because WebSecurityConfigurerAdapter is not present anymore.
I create simple GitHub repository with the sample:
https://github.com/martinspudich/spring-boot-3-digest
I will appreciate any help you can provide. Thank you in advance.
I create simple HelloController:
package com.example.springboot3digest.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HelloController {
#GetMapping("/")
public String hello() {
return "Hello World!";
}
}
And WebSecurityConfig:
package com.example.springboot3digest.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http, UserDetailsService userDetailsService) throws Exception {
http
.authorizeHttpRequests(request -> {
request.anyRequest().authenticated();
})
.exceptionHandling(e -> e.authenticationEntryPoint(entryPoint()))
.addFilterBefore(digestAuthenticationFilter(userDetailsService), BasicAuthenticationFilter.class);
return http.build();
}
#Bean
UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password("user")
.roles("USER").build();
return new InMemoryUserDetailsManager(user);
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
DigestAuthenticationEntryPoint entryPoint() {
DigestAuthenticationEntryPoint result = new DigestAuthenticationEntryPoint();
result.setRealmName("My App Realm");
result.setKey("3028472b-da34-4501-bfd8-a355c42bdf92");
return result;
}
DigestAuthenticationFilter digestAuthenticationFilter(UserDetailsService userDetailsService) {
DigestAuthenticationFilter result = new DigestAuthenticationFilter();
result.setUserDetailsService(userDetailsService);
result.setAuthenticationEntryPoint(entryPoint());
return result;
}
}
I was following spring.io documentation:
https://docs.spring.io/spring-security/reference/servlet/authentication/passwords/digest.html
But authentication is not working. When I try to authenticate it returns the error 403 Forbidden.

The DigestAuthenticationFilter does not generate "authenticated" tokens unless you explicitly tell it to do so as described here.
Add the line:
result.setCreateAuthenticatedToken(true);
to your DigestAuthenticationFilter instantiation:
DigestAuthenticationFilter digestAuthenticationFilter(UserDetailsService userDetailsService) {
DigestAuthenticationFilter result = new DigestAuthenticationFilter();
result.setUserDetailsService(userDetailsService);
result.setCreateAuthenticatedToken(true);
result.setAuthenticationEntryPoint(entryPoint());
return result;
}

Related

Always getting redirected from /authorized to /login page using new spring authorization server

I am using new spring authorization server. And everything was working fine with version 0.3.1. But after migration to 1.0.0. When I am trying to login (and I am supposed to be redirected to /authorized?code=) I am always getting redirected back to login. Could somebody please explain me what is going wrong? Maybe config for security should be specified in one place only?
Thank you.
AuthorizationServerConfig
package oauth2.config;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import oauth2.converter.AuthorizationClientConverter;
import oauth2.handler.FederatedIdentityAuthenticationSuccessHandler;
import oauth2.repository.AuthorizationClientRepository;
import oauth2.repository.ClientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.RequestMatcher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.util.UUID;
#Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private AuthorizationClientConverter authorizationClientConverter;
#Autowired
private FederatedIdentityAuthenticationSuccessHandler federatedIdentityAuthenticationSuccessHandler;
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
http
.securityMatcher(endpointsMatcher)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.authorizeHttpRequests(auth -> {
auth.anyRequest().authenticated();
})
.formLogin(Customizer.withDefaults())
.oauth2Login(Customizer.withDefaults())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.apply(authorizationServerConfigurer);
return http.build();
}
#Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
JwtClaimsSet.Builder claims = context.getClaims();
if (context.getTokenType().equals(OAuth2TokenType.ACCESS_TOKEN)) {
claims.claim("claim", "zabur_claim");
}
};
}
#Bean
public RegisteredClientRepository registeredClientRepository(ClientRepository clientRepository) {
RegisteredClient registeredClient = RegisteredClient.withId("messaging-client")
.clientId("messaging-client")
.clientSecret(passwordEncoder.encode("secret"))
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://127.0.0.1:8080/authorized")
.scope("message.read")
.scope("message.write")
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
AuthorizationClientRepository registeredClientRepository = new AuthorizationClientRepository(authorizationClientConverter, clientRepository);
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
#Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
#Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("http://localhost:8080")
.build();
}
#Bean
public TokenSettings tokenSettings() {
return TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(5))
.build();
}
private RSAKey generateRsa() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// #formatter:off
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// #formatter:on
}
private KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}
SecurityConfig
package oauth2.config;
import oauth2.handler.FederatedIdentityAuthenticationSuccessHandler;
import oauth2.handler.FormLoginAuthenticationSuccessHandler;
import oauth2.service.impl.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private FederatedIdentityAuthenticationSuccessHandler federatedIdentityAuthenticationSuccessHandler;
#Autowired
private FormLoginAuthenticationSuccessHandler formLoginAuthenticationSuccessHandler;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.authorizeHttpRequests(auth -> {
auth.requestMatchers("/logout", "/signUp", "/authorized").permitAll();
auth.anyRequest().authenticated();
})
.formLogin(formLogin -> formLogin.successHandler(formLoginAuthenticationSuccessHandler))
.oauth2Login(oauth2Login -> oauth2Login.successHandler(federatedIdentityAuthenticationSuccessHandler));
return http.build();
}
#Bean
public DaoAuthenticationProvider authenticationProvider(CustomUserDetailsService customUserDetailsService) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(passwordEncoder);
authenticationProvider.setUserDetailsService(customUserDetailsService);
return authenticationProvider;
}
}
I am trying to login with OAuth2 and expecting to be redirected to the /authorized?code= but after that I am redirected to /login.
Might you are using lot more code to serve your purpose. I integrated OAuth 2 in my Application using Spring security 6.0.0 and Spring Authorization Server 1.0.0. It made me sweating lot. But I got success. For that I shared my Authorization server configuration as it did.
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http
.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
http
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE + 1)
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http
.cors().and().csrf().disable()
.headers().frameOptions().sameOrigin()
.httpStrictTransportSecurity().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
I think it may help you a little bit or you may get an idea what actually going on in your code.
SecurityFilterChain by default masks any request for authentication, it acts as a safety net, shadowing any permitAll() matcher. This is somehow not clear in the documentation, as per my understanding for the documentation, and needs to be better clarified.
Allowable paths must be declared in a SecurityFilterChain Bean, while authenticated and authorized paths must be kept in another SecurityChain Bean. To differentiate between allowed and authorized paths, use '.securityMaters()', as shown in the example below:
#Bean
#Order(0)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.securityMatcher("/logout", "/signUp", "/authorized")
.authorizeHttpRequests(auth -> {
auth.anyRequest().permitAll();
});
return http.build();
}
#Bean
#Order(1)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/signUp", "/logout"))
.authorizeHttpRequests(auth -> {
auth.anyRequest().authenticated();
})
.formLogin(formLogin -> formLogin.successHandler(formLoginAuthenticationSuccessHandler))
.oauth2Login(oauth2Login -> oauth2Login.successHandler(federatedIdentityAuthenticationSuccessHandler));
return http.build();
}
Try it and let me know how it goes with you!

Spring Security with multiple security models configured with SecurityFilterChain ignores authentication configuration

I am trying to build a Spring Boot application, that has different security models for different URLs. So I try to avoid creating a global AuthenticationManager bean, but instead configure it in the Spring Security DSL as described here: https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
However MyAuthProvider does not get called in either a/ or b/.
I would expect it to be called in both examples.
Surprisingly a/ returns 403 Access Denied and b/ returns 200 OK
What am I doing wrong?
Complete example provided here as a single class Spring Boot application (2.7.3)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Set;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public SecurityFilterChain secureA(HttpSecurity http) throws Exception {
http.authorizeRequests(auth ->
auth.antMatchers("/a").hasRole("a")
);
http.authenticationProvider(new MyAuthProvider("a"));
return http.build();
}
#Bean
public SecurityFilterChain secureB(HttpSecurity http) throws Exception {
http.authorizeRequests(auth ->
auth.antMatchers("/b").hasRole("b")
);
http.authenticationManager(new ProviderManager(new MyAuthProvider("b")));
return http.build();
}
#RestController
public class RestService {
#GetMapping("/a")
public String a() {
return "hello a";
}
#GetMapping("/b")
public String b() {
return "hello b";
}
#GetMapping("/c")
public String c() {
return "hello c";
}
}
class MyAuthProvider implements AuthenticationProvider {
private String cfg;
public MyAuthProvider(String cfg) {
this.cfg = cfg;
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
System.out.println("authenticate " + cfg);
var roles = Set.of(new SimpleGrantedAuthority("ROLE_" + cfg));
return new UsernamePasswordAuthenticationToken("user", "pass", roles);
}
#Override
public boolean supports(Class<?> authentication) {
System.out.println("supports " + cfg);
return true;
}
}
}

How do session time out and and ask for login again in Spring boot

I am trying to build simple JSON rest API using spring boot, I have build the application it works fine, now I need to do the simple Basic authentication and I did this with Spring security. Please find the Code below, My pain point here is when I run the application, I ask for the login first time then I tried to reload the URL again it does not ask for user name password. How to make the URL session expired and ask to prompt for login again. Note : I am not using any UI, It just an API
Security Configuration Class
package com.erplogic.erp.topcon.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
public class SecurityConfiguration {
#Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authz) -> authz.anyRequest().authenticated()
).sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
)
.httpBasic();
return http.build();
}
#Bean
InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.builder().username("user").password(encoder().encode("pass")).roles("USER").build();
return new InMemoryUserDetailsManager(user);
}
#Bean
PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}
Controller Class
package com.erplogic.erp.topcon.controller;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.erplogic.erp.topcon.service.SapApiService;
import com.erplogic.poc.objects.Root;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.erplogic.maven.plclog.wsdl2java.StandardFaultMessage_Exception;
#RestController
public class OutboundController {
#Autowired
private SapApiService sapApiService;
#RequestMapping(path ="/outbound",produces = MediaType.APPLICATION_JSON_VALUE,method = RequestMethod.GET)
public Root getOutbound() throws KeyManagementException, NoSuchAlgorithmException, StandardFaultMessage_Exception, JsonProcessingException {
return ((SapApiService) sapApiService).processOutboudService();
}
#RequestMapping(value = "/outbound/{outboundId}",produces = MediaType.APPLICATION_JSON_VALUE,method = RequestMethod.GET)
public String getOutboundId(#PathVariable String outboundId) throws KeyManagementException, JsonProcessingException, NoSuchAlgorithmException, StandardFaultMessage_Exception {
return ((SapApiService) sapApiService).processOutboudServiceByID(outboundId);
}
}

Spring-boot Digest authentication failure using Digest filter

I am new to this technology . I have trying to implement Digest Authentication for my Springboot application . I am getting below error while I am trying to call my application :There is no PasswordEncoder mapped for the id \"null\"","path":"/countryId/"}* Closing connection 0
curl command I am using to invoke : curl -iv --digest -u test:5f4dcc3b5aa765d61d8327deb882cf99 -d {"CountryCode": "INDIA"} http://localhost:9090/countryId/
Classes Details :
package com.sg.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
import org.springframework.stereotype.Component;
#Component
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomDigestAuthenticationEntryPoint customDigestAuthenticationEntryPoint;
/*#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}*/
#Bean
public UserDetailsService userDetailsServiceBean()
{
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("test").password("{noop}password").roles("USER").build());
return manager;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/hello/**").permitAll().anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(customDigestAuthenticationEntryPoint).and()
.addFilter(digestAuthenticationFilter());
}
//#Bean
DigestAuthenticationFilter digestAuthenticationFilter() throws Exception {
DigestAuthenticationFilter digestAuthenticationFilter = new DigestAuthenticationFilter();
digestAuthenticationFilter.setUserDetailsService(userDetailsServiceBean());
digestAuthenticationFilter.setAuthenticationEntryPoint(customDigestAuthenticationEntryPoint);
return digestAuthenticationFilter;
}
}
package com.sg.config;
import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
#Component
public class CustomDigestAuthenticationEntryPoint extends DigestAuthenticationEntryPoint {
#Override
public void afterPropertiesSet() throws Exception {
setRealmName("Digest-Realm");
setKey("MySecureKey");
setNonceValiditySeconds(300);
super.afterPropertiesSet();
}
}
I have resolved the issue. Let me explain what went wrong first, in current Spring security, you can not use a plain text password, so have to keep some encrypting logic. But unfortunately Digest doesn't work with a encrypted password.
I have found a work around, instead using a Bean (Bycrypt), I have directly implemented PasswordEncoder interface, in a way, it should able to hold plain text password.
#Bean
public PasswordEncoder passwordEncoder() {
return new PasswordEncoder() {
#Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.toString().equals(encodedPassword);
}
};
}

Spring security 3.2.5 and token based authentication

I'm trying to secure a REST API using Spring security 3.2.5 and a java based configuration.
Actually i've found many examples developed with an "old" xml approach, but nothing with a complete java configuration.
Where can i find some useful tutorial?
The project creates a REST API and some jsp usesd to allow the admin to populate an underlyin DB (Hibernate is used as ORM):
Here is my Config class:
package com.idk.fantappapaback.spring;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.tomcat.dbcp.dbcp.BasicDataSource; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.orm.hibernate4.HibernateTransactionManager; import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.multipart.support.StandardServletMultipartResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.JstlView; import org.springframework.web.servlet.view.UrlBasedViewResolver;
import com.google.common.base.Preconditions; import com.idk.fantappapaback.spring.security.SecurityConfig;
#Configuration #EnableWebMvc #EnableTransactionManagement #PropertySource({ "classpath:persistence-mysql.properties" }) #ComponentScan({ "com.idk.fantappapaback.persistence","com.idk.fantappapaback.rest","com.idk.fantappapaback.spring.controllers","com.idk.fantappapaback.spring.security" }) #Import({ SecurityConfig.class }) public class BackEndConfig extends WebMvcConfigurerAdapter{
#Autowired
private Environment env;
public BackEndConfig() {
super();
}
//l'application context estrae il session factory da questo bean
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.idk.fantappapaback.persistence.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource restDataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(final SessionFactory sessionFactory) {
final HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
//***Proprieta per l'output delle query in sql che qui disabilito
// hibernateProperties.setProperty("hibernate.show_sql", "true");
// hibernateProperties.setProperty("hibernate.format_sql", "true");
// hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
return hibernateProperties;
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public StandardServletMultipartResolver multipartResolver(){
return new StandardServletMultipartResolver();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/"); // registry.addResourceHandler("/css/**") // .addResourceLocations("/css/"); // registry.addResourceHandler("/img/**") // .addResourceLocations("/img/");
registry.addResourceHandler("/js/**")
.addResourceLocations("/js/");
}
}
this is my very basic Security config that i use to have a form log in on the jsp views:
package com.idk.fantappapaback.spring.security;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Import({ SecurityConfig.class }) nella BackEndConfig #Configuration #EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter{ #Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("masquenada").password("123456").roles("USER"); // auth.inMemoryAuthentication().withUser("masquenada").password("123456").roles("ADMIN"); auth.inMemoryAuthentication().withUser("masquenada").password("123456").roles("SUPERADMIN"); }
#Override protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // .antMatchers("/players/**").access("hasRole('ROLE_USER')") .antMatchers("/createSeason/**").access("hasRole('ROLE_SUPERADMIN')") .and().formLogin().permitAll() .and().httpBasic();
} }
here is my SecurityWebApplicationInitializer :
package com.idk.fantappapaback.spring.security;
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
The main question is : how to add the token based autorization?
I've added Spring oAuth 2 and Spring integration to my pom but i need some hint about introducing spring oAuth keeping the form login.
You need to "configure" your SecurityWebApplicatioInitializer.
http://spring.io/blog/2013/07/03/spring-security-java-config-preview-web-security/

Resources