I know there are several questions about this, but none of them helped, everything seemed ok to me... I hope I'm wrong about this.
I've followed this tutorial to create authentication with JWT for my Spring Boot application, but I'm stuck with this warning
o.s.s.c.bcrypt.BCryptPasswordEncoder : Encoded password does not look like BCrypt
This is the class that extends WebSecurityConfigurerAdapter:
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
}
And this is the class that implements UserDetailsService:
public class UserDetailsServiceImpl implements UserDetailsService {
private ApplicationUserRepository applicationUserRepository;
public UserDetailsServiceImpl(ApplicationUserRepository applicationUserRepository) {
this.applicationUserRepository = applicationUserRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername");
ApplicationUser applicationUser = applicationUserRepository.findByUsername(username);
if (applicationUser == null) {
System.out.println("User non trovato");
throw new UsernameNotFoundException(username);
}
System.out.println("Username: " + applicationUser.getUsername());
return new User(applicationUser.getUsername(), applicationUser.getPassword(), emptyList());
}
}
Also, I'm wondering where the class WebSecurity is istantiated with the correct parameters passed. Is this managed automatically by Spring?
Found the problem, it was that my class UserDetailsServiceImpl did not have the "#Service" annotation. Now it's working fine.
Related
When making post request to login this error shows up telling me that userService is null.
When I create an object of UserService instead of autowiring it it passes it but tell me that the repository called in userService is null. The repository is autowired and i cannot instanciate it because its an interface.
Here is the service class:
#Service
public class MyUserDetailsService implements UserDetailsService {
#Autowired
UserService userService;
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return new MyUserDetails(userService.getByUsernameOrEmail(s));
}
}
And this is the security configuration class:
Also I am creating an object of MyUserService because spring cannot autowire it telling me that no bean have such name.
#Configuration
#EnableWebSecurity
public class UserSercurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new MyUserDetailsService());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().hasRole(UserType.ADMIN.toString())
.and().formLogin();
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
You cannot instantiate method or variables in your repository as it is an interface but you can autowire your repository class to use your method declared in userRepository interface, you have to autowire your repository class.You can do it this way as I have done in the below code.
Your service class should be like this:
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Users user = userRepository.getUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Could not find user");
}
return new MyUserDetails(user);
}
And your repository should be like this:
#Repository
public interface UserRepository extends JpaRepository<Users, Long> {
#Query("SELECT u FROM Users u WHERE u.name = ?1")
public Users getUserByUsername(String username);
}
And also autowire UserDetailsService in your configuration class and pass the instance userDetailsService in your configure(AuthenticationManagerBuilder auth) method, UserDetailsService provides you instance of your MyUserDetailService class.
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.and()
.formLogin().permitAll()
.defaultSuccessUrl("/", true)
.and()
.logout().permitAll()
.logoutSuccessUrl("/");
}
Try to implement in this way, If this is solution of your question please let me know and if you still have doubt feel free to ask.
I have a spring project using Spring Security. I want to inject dependencies into my WebSecurityConfigurerAdapter extending class but the dependencies do not seem to be getting injected. My controllers also use dependency injection and it does work there.
My SecSecurity class:
#Configuration
#Component
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserPrincipalDetailsService userPrincipalDetailsService;
LogoutSuccessHandler handler = new LogoutSuccess();
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http. logout().and().
httpBasic()
.and()
.authorizeRequests()
.antMatchers( "/", "/home", "/user", "/vestigingen", "/available", "/logout").permitAll()
.anyRequest().authenticated()
.and().logout().logoutSuccessHandler(handler).deleteCookies("JSESSIONID").invalidateHttpSession(false).permitAll()
.and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
#Bean
public UserDetailsService userDetailsService() {
return new UserPrincipalDetailsService();
}
DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailsService);
return daoAuthenticationProvider;
}
}
It cannot find beans for the userPrincipalDetailsService class.
UserPrincipalDetailService class:
#Component
public class UserPrincipalDetailsService implements UserDetailsService {
private UserRepositorySQL userRepository = new UserRepositorySQL();
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserEntity user = userRepository.findUserByUsername(s);
UserPrincipal userPrincipal = new UserPrincipal(user);
return userPrincipal;
}
}
to clarify: I can't inject any dependencies within my SecSecurityConfig class eventhough i have tried annotating it in many different ways.
Define the bean name #Component("userPrincipalDetailsService") in the UserPrincipalDetailsService class.
#Component("userPrincipalDetailsService")
public class UserPrincipalDetailsService implements UserDetailsService {
private UserRepositorySQL userRepository = new UserRepositorySQL();
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserEntity user = userRepository.findUserByUsername(s);
UserPrincipal userPrincipal = new UserPrincipal(user);
return userPrincipal;
}
}
I am trying to implement OAuth2 - SpringBoot authentication.
I have configured a path with permitAll(), but even though it is configured, it shows error
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
I am using postman to test and simply trying to fetch all users in DB. When I call, the control is not coming to RestController. I would like to just get the users list and permitAll() is provided.
Can anyone please help ?
I am posting the code below.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().
antMatchers(HttpMethod.POST, "/api/**").permitAll().
antMatchers(HttpMethod.POST,"/admin/**").hasAnyRole("ADMIN").
anyRequest().authenticated();
}
#Override
public void configure(AuthenticationManagerBuilder builder) throws Exception{
builder.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select usrnam,usrpwd, case when usrsta='A' then true else false end from chsusrmst where usrnam=?")
.authoritiesByUsernameQuery("select usrnam,usrtyp from chsusrmst where usrnam=?");
}
}
#RestController
#RequestMapping("/api")
public class UserController {
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Autowired
private UserRepository userRepository;
#PostMapping("/user/register")
public String register(#RequestBody User user) {
String encodedPassword = passwordEncoder.encode(user.getUserPassword());
user.setUserPassword(encodedPassword);
userRepository.save(user);
return "User created";
}
#PostMapping("/admin/findUser")
public User findUser(#RequestBody User user) {
return userRepository.findByUserName(user.getUserName());
}
#PostMapping("/user/findAllUsers")
public List<User> findAllUsers() {
return userRepository.findAll();
}
}
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final PasswordEncoder passwordEncoder;
private final UserDetailsService userDetailsService;
#Value("${jwt.clientId:client}")
private String clientId;
#Value("${jwt.client-secret:secret}")
private String clientSecret;
#Value("${jwt.signing-key:123}")
private String jwtSigningKey;
#Value("${jwt.accessTokenValidititySeconds:43200}") // 12 hours
private int accessTokenValiditySeconds;
#Value("${jwt.authorizedGrantTypes:password,authorization_code,refresh_token}")
private String[] authorizedGrantTypes;
#Value("${jwt.refreshTokenValiditySeconds:2592000}") // 30 days
private int refreshTokenValiditySeconds;
public AuthorizationServerConfig(AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder, UserDetailsService userDetailsService) {
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
this.userDetailsService = userDetailsService;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(clientId)
.secret(passwordEncoder.encode(clientSecret))
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(refreshTokenValiditySeconds)
.authorizedGrantTypes(authorizedGrantTypes)
.scopes("read", "write")
.resourceIds("api");
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.accessTokenConverter(accessTokenConverter())
.userDetailsService(userDetailsService)
.authenticationManager(authenticationManager);
}
#Bean
JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
return converter;
}
}
#Configuration
#EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer serverSecurityConfigurer) {
serverSecurityConfigurer.resourceId("api");
}
}
Thanks for your consideration. I found the issue. HttpSecurity configuration was missing in Resource server and it has been resolved by adding below section.
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/user**").permitAll()
.antMatchers("/user/**").permitAll()
.antMatchers("/admin**").hasAuthority("ADMIN")
.antMatchers("/api/**").authenticated()
.anyRequest().authenticated();
I am very new to spring and it is my first attempt at spring security with oauth2. I have implemented OAuth2 with spring security and I do get the access token and the refresh token. However, while sending the refresh token to get the new access token I got "o.s.s.o.provider.endpoint.TokenEndpoint - IllegalStateException, UserDetailsService is required."
The solution to similar problem by other users appeared to be attaching UserDetailsService with the endpoint.
So I did the same and now when I try to send the request to with grant_type: refresh_token and refresh_token: THE TOKEN along with the client id and secret, I get an error that the user was not found.
Please refer the WebSecurityConfiguration class below:
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsService customUserDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean ();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService)
.passwordEncoder(encoder());
}
#Override
protected void configure (HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/login**")
.permitAll()
.anyRequest()
.authenticated();
}
public PasswordEncoder encoder() {
return NoOpPasswordEncoder.getInstance();
}
}
Please refer the AuthorizationServerConfiguration class below:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore());
.userDetailsService(userDetailsService);
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
}
Please refer the ResourceServerConfiguration class below:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{
#Autowired
DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("scout").tokenStore(tokenStore());
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests (). antMatchers ("/oauth/token", "/oauth/authorize **").permitAll();
// .anyRequest (). authenticated ();
http.requestMatchers (). antMatchers ("/api/patients/**") // Deny access to "/ private"
.and (). authorizeRequests ()
.antMatchers ("/api/patients/**"). access ("hasRole ('PATIENT')")
.and (). requestMatchers (). antMatchers ("/api/doctors/**") // Deny access to "/ admin"
.and (). authorizeRequests ()
.antMatchers ("/api/doctors/**"). access ("hasRole ('DOCTOR')");
}
}
The CustomUserDetailsService class for reference if required:
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UsersRepository userRepository;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Optional<Users> usersOptional = userRepository.findByEmail(email);
Users user = null;
if(usersOptional.isPresent()) {
System.out.println(usersOptional.isPresent());
user = usersOptional.get();
}else {
throw new RuntimeException("Email is not registered!");
}
return new CustomUserDetails(user);
}
}
As I think, the server should only check for the validity of the refresh token as we don't pass the user details with refresh token. So I don't know why it requires the userDetails in the first place.
Please help and guide if I am missing something!
Thanks in advance.
I don't sure. But as I see your code in WebSecurityConfiguration could wired default InMemoryUserDetailsManager UserDetailsService .That could be reason why you have 2 different provider. In one you write, from the other you read users. Please try change your code as I show below and let me know if it help:
Was:
#Autowired
private UserDetailsService customUserDetailsService;
My vision how should be:
#Autowired
private CustomUserDetailsService customUserDetailsService;
I am trying to achieve authentication system using OAuth2 as well as simple Spring Security(Web Security adapter). But as I am trying to configure, I am not able to use both the services together. As per configuration file code shared below, But It will work either OAuth2 or simple auth using spring security(Web Security adapter). I want both the authentication system should work based on URL identification.
Thanks in advance!
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class ConfigurationClass {
// Its working as simple auth spring security
#EnableWebSecurity
#Configuration
#Order(1)
protected static class StatelessAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private TokenAuthenticationService tokenAuthenticationService;
#Autowired
private OtpManage OtpManage;
#Autowired
private RoleRepository RoleRepository;
public StatelessAuthenticationSecurityConfig() {
super(true);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// allow anonymous resource requests
.antMatchers("/").permitAll()
// allow anonymous POSTs to login
.antMatchers(HttpMethod.POST, "/user/registration").permitAll()
.antMatchers(HttpMethod.POST, "/user/changepassword").permitAll()
.antMatchers(HttpMethod.POST, "/user/resetpassword").permitAll()
// .antMatchers(HttpMethod.POST,
// "/api/otpResetPassword").permitAll()
.antMatchers(HttpMethod.POST, "/user/saveusergroup").permitAll()
.antMatchers(HttpMethod.POST, "/user/bugreport").permitAll()
.antMatchers(HttpMethod.POST, "/user/createtoken").permitAll()
// .anyRequest().authenticated().and()
.anyRequest().hasAnyRole("USER","SYSTEM_ADMIN","ADMIN").and()
// custom JSON based authentication by POST of
// {"username":"<name>","password":"<password>"} which sets the
// token header upon authentication
.addFilterBefore(new StatelessLoginFilter("/api/login", tokenAuthenticationService, userDetailsService,
authenticationManager(), OtpManage), UsernamePasswordAuthenticationFilter.class)
// custom Token based authentication based on the header
// previously given to the client
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
#Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
// Its not working, But if I removed #Order(1) annotation from StatelessAuthenticationSecurityConfig class then this one will work as default
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
#Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
System.out.println("#EnableResourceServer");
http
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
.disable()
.headers()
.frameOptions().disable().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/hello/").permitAll()
.antMatchers("/secure/**").authenticated();
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
#Autowired
private DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("#AuthorizationServerConfigurerAdapter");
clients
.inMemory()
.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
.authorizedGrantTypes("password", "refresh_token")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800));
}
#Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
}
}
Update:
I have made few changes to my code with #EnableOAuth2Client, #Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) and I have achieved what exactly I want to do. But now the issue is I am not able call to post url: "/api/login" with user credentials. I am getting error as url not found. as per my code in WebSecurityConfig class, I have added filter in configure(HttpSecurity http) method for loginFilter class which extends AbstractAuthenticationProcessingFilter. But this filter which is mapped with "/api/login" url not working at all. Why this one filter is not working I don`t understand. Someone could you help me regarding the same.
#WebSecurityConfigClass
/**
* Implementation of HttpSecurity configure method
* Implementation custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
* #author Santosh
*
*/
#EnableOAuth2Client
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true, securedEnabled = true, proxyTargetClass = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private TokenAuthenticationService tokenAuthenticationService;
#Autowired
private MessageSource messages;
#Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private RESTAuthenticationSuccessHandler restAuthenticationSuccessHandler;
#Autowired
private RESTAuthenticationFailureHandler restAuthenticationFailureHandler;
#Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
public WebSecurityConfig() {
super(true);
}
/*#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
auth.inMemoryAuthentication().withUser("testUser").password("testUser").roles("USER");
}
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
// setup security
http
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and().httpBasic();
http
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.anonymous().and()
.servletApi().and()
.headers().and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/login").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.authorizeRequests()
.anyRequest().hasAnyRole("USER").and()
//all other request need to be authenticated
// custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
.addFilterBefore(new LoginFilter("/api/login", tokenAuthenticationService, userDetailsService, authenticationManager(), restAuthenticationSuccessHandler, restAuthenticationFailureHandler), UsernamePasswordAuthenticationFilter.class)
// custom Token based authentication based on the header previously given to the client
.addFilterBefore(new ApplicationFilter (tokenAuthenticationService, messages), UsernamePasswordAuthenticationFilter.class);
}
// To allow Pre-flight [OPTIONS] request from browser
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
web.ignoring()//allow anonymous GETs to API
.antMatchers(HttpMethod.GET, "/api/status/**");
}
#Bean
public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
return new CustomBasicAuthenticationEntryPoint();
}
#Bean(name="authenticationManagerBean")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
#OAuth2ServerConfiguration
#Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "restservice";
private static final String ROLE_ADMIN = "ADMIN";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private CustomOAuth2AccessDeniedHandler accessDeniedHandler;
#Autowired
private RESTOAuth2AuthenticationEntryPoint restAuthenticationEntryPoint;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/hello").permitAll()
.antMatchers("/users/current/**","/oauth/token","/oauth/authorize","/oauth/refresh_token").permitAll()
.antMatchers("/api/greeting").authenticated().and().exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(restAuthenticationEntryPoint);
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private DataSource dataSource;
#Autowired
private TokenStore tokenStore;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
// #Autowired
// private UserApprovalHandler userApprovalHandler;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(this.tokenStore).authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// .userApprovalHandler(userApprovalHandler)
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// jdbc(dataSource)
clients.inMemory().withClient("clientapp").authorizedGrantTypes("password", "refresh_token")
.authorities("USER").scopes("read", "write").resourceIds(RESOURCE_ID).secret("123456")
.accessTokenValiditySeconds(20)// Access token is only valid
// for 2 minutes.
.refreshTokenValiditySeconds(1200);// Refresh token is only
// valid for 10
// minutes.;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
}
On your WebSecurityAdapter you want to build requestMatchers to determine on which requests that instance of HttpSecurity will invoke.
For example :
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/secure/path", "/more/secure/path");
// Rest of your configuration.
}