Error occured when Spring Security CustomLoginFilter is applied! somebody help me - spring

I want to apply CustomLoginProcessingFilter in my application but i can't figure out how it works!
I'm using Spring boot 2.7.2, the lastest version when i started studying this.
here's my code
Another custom providers or custom detail services work so well.
But, once i enroll new bean fore login processing filter, AjaxLoginProcessingFilter, they tell me that i need to specify authentitcationManager!
so, i added at filterChain method this in SecurityConfig.java, but it doesn't work.
enter image description here
/**
----------------- SecurityConfig -------------------------
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#RequiredArgsConstructor
public class SecurityConfig {
private final CustomAuthenticationSuccessHandler authenticationSuccessHandler;
private final CustomAuthenticationFailureHandler authenticationFailureHandler;
private final FormAuthenticationDetailsSource authenticationDetailsSource;
private final AjaxLoginProcessingFilter ajaxLoginProcessingFilter;
#Bean
AuthenticationManager authenticationManager(AuthenticationManagerBuilder builder) throws Exception {
return builder.build();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(registry -> {
registry.antMatchers("/","/users","user/login/**","/login*").permitAll()
.antMatchers("/mypage").hasRole("USER")
.antMatchers("/messages").hasRole("MANAGER")
.antMatchers("/config").hasRole("ADMIN")
.anyRequest().authenticated();
}).formLogin(login -> {
login.loginPage("/login")
.loginProcessingUrl("/login_proc")
.defaultSuccessUrl("/")
.authenticationDetailsSource(authenticationDetailsSource)
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
.permitAll();
}).exceptionHandling(exception -> {
exception.accessDeniedHandler(accessDeniedHandler());
})
.addFilterBefore(ajaxLoginProcessingFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
#Bean
public AccessDeniedHandler accessDeniedHandler(){
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler();
accessDeniedHandler.setErrorPage("/denied");
return accessDeniedHandler;
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() throws Exception {
return (web) -> web.ignoring().antMatchers("/resources/**");
}
#Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
/*Explanation:
In the old version you inject AuthenticationManagerBuilder, set userDetailsService, passwordEncoder and build it.
But authenticationManager is already created in this step.
It is created the way we wanted (with userDetailsService and the passwordEncoder).
https://stackoverflow.com/questions/72381114/spring-security-upgrading-the-deprecated-websecurityconfigureradapter-in-spring
*/
#Bean
CustomUserDetailsService customUserDetailsService() {
return new CustomUserDetailsService();
}
#Bean
public AuthenticationProvider authenticationProvider() {
return new CustomAuthenticationProvider();
}
}
-++------------------ AjaxLoginProcessingFilter ---------------------
#Component("loginProcessingFilter")
public class AjaxLoginProcessingFilter extends AbstractAuthenticationProcessingFilter {
private ObjectMapper objectMapper = new ObjectMapper();
public AjaxLoginProcessingFilter() {
super(new AntPathRequestMatcher("/api/login"));
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if(isAjax(request)){
throw new IllegalStateException("Authentication is not supported");
}
AccountDto accountDto = objectMapper.readValue(request.getReader(), AccountDto.class);
if(StringUtils.isEmpty(accountDto.getUsername()) || StringUtils.isEmpty(accountDto.getPassword())){
throw new IllegalArgumentException("Username or password is not empty");
}
AjaxAuthenticationToken authenticationToken = new AjaxAuthenticationToken(accountDto.getUsername(), accountDto.getPassword());
return getAuthenticationManager().authenticate(authenticationToken);
}
private boolean isAjax(HttpServletRequest request) throws IOException {
if("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){
return true;
}
return false;
}
}

Related

Spring Boot Resource Server Invalid Access Token

My configuration for the Spring Boot resource server is provided:
#Configuration
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "couponservice";
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers(HttpMethod.GET, "/couponapi/coupons/{code:^[A-Z]*$}").hasAnyRole("USER", "ADMIN")
.mvcMatchers(HttpMethod.POST, "/couponapi/coupons").hasRole("ADMIN")
.anyRequest().denyAll().and().csrf().disable();
}
// #Bean
// public TokenStore tokenStore() {
// return new JwtTokenStore(jwtAccessTokenConverter());
// }
//
// #Bean
// public JwtAccessTokenConverter jwtAccessTokenConverter() {
//
// JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
// jwtAccessTokenConverter.setVerifierKey(publicKey);
//
// return jwtAccessTokenConverter;
// }
}
The application.properties file is provided:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=testuser
spring.datasource.password=testpassword
server.port=9091
spring.thymeleaf.cache=false
spring.main.allow-bean-definition-overriding=true
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:9092/oauth/token_key
# security.oauth2.resource.jwt.key-uri=http://localhost:9092/oauth/token_key
If I keep the JwtAccessTokenConverter and use the correct public key, the code is working. But, I would like to connect using the auth URL provided in the properties files.
Now, when I make the GET request, I see the invalid access toekn. Whats the issue here and how do I resolve it?
Looks like you need to tell Spring WHAT MECHANISM to use to authorize. Maybe compare to this Curity example, which should provide enough clues to overcome your problem:
Code
Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
String issuerUri;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.antMatchers("/services").hasAuthority("SCOPE_services:read")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer
.jwt(jwt ->
jwt.decoder(JwtDecoders.fromIssuerLocation(issuerUri))
)
);
}
}

How do I implement conditional authentication in spring security based on user selection between LDAP and JDBC?

Hope you all are doing good and safe. I have an application which will allow a user to login either by using his LDAP credentials or using his credentials stored on database. I was able to configure separate jdbc and ldap authenticator but how can I implement it conditionally? Say, a user selects LDAP radio button on login page then it should trigger LDAP authentication and if user selects database authentication, then it should trigger jdbc authentication. Any help would be highly appreciated.
JDBC authenticator:-
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.authorizeRequests()
.antMatchers("/admin").hasAnyRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN", "USER")
.antMatchers("/").permitAll()
.and().formLogin();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
**LDAP authenticator:-**
#EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private UserDetailsService userDetailsService;
#Autowired
AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
#Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new AuthenticationFailureHandler() {
String message = "";
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) {
message = "User Not Found";
} else if (exception.getClass().isAssignableFrom(DisabledException.class)) {
message = "Account Disabled";
} else if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
message = "Bad Credentials";
}
else if (exception.getClass().isAssignableFrom(LockedException.class)) {
message = "Account Locked";
}
else {
message = "Internal Server Error";
}
response.sendRedirect("/WisoKeyinPortal/login?error=" + message);
}
};
}
#Bean
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
return authenticationProvider;
}
/*---------------------------For QA comment from here-------------------------------*/
#Bean public AuthenticationManager authenticationManager() { return new
ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean public AuthenticationProvider
activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new
ActiveDirectoryLdapAuthenticationProvider("xyz.com", "ldap://xyz.com");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setSearchFilter("sAMAccountName={1}"); return provider; }
/*----------------------------For QA comment ends here-----------------------------*/
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] staticResources = { "/css/**", "/images/**", "/fonts/**", "/scripts/**", };
http.csrf().disable().authorizeRequests().antMatchers("/login**").permitAll().antMatchers(staticResources)
.permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll()
.successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler).and()
.logout().invalidateHttpSession(true).clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login").permitAll();
//.and().sessionManagement().invalidSessionUrl("/login?error=session");
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
//authManagerBuilder.inMemoryAuthentication().withUser("admin").password("pass").roles("ADMIN");
/*---------------------------For QA comment from here-------------------------------*/
authManagerBuilder.authenticationProvider(
activeDirectoryLdapAuthenticationProvider())
.userDetailsService(userDetailsService());
/*---------------------------For QA comment from here-------------------------------*/
}
}

Spring Security Authentication Server with multiple authentication providers for client_credentials

I am trying to setup an authentication server using Spring Security authentication and need to have multiple authentication providers for client_credentials.
I have done quite a bit of searching and have yet to find how to configure spring security to add my custom authentication provider to the client credentials authentication provider list. Every approach I found results in the same 2 providers for the client credentials authentication. The anonymous and the dao authentication providers.
I would appreciate any help in figuring out how to configure the the spring security authentication server for multiple client credential authentication providers.
AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
{
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(final AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(passwordEncoder())
.allowFormAuthenticationForClients();
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("sampleClientId").authorizedGrantTypes("implicit")
.scopes("read", "write", "foo", "bar")
.autoApprove(false)
.accessTokenValiditySeconds(3600)
.redirectUris("http://localhost:8083/")
.and()
.withClient("fooClientIdPassword")
.secret(passwordEncoder().encode("secret"))
.authorizedGrantTypes("password", "authorization_code", "refresh_token")
.scopes("foo", "read", "write")
.accessTokenValiditySeconds(3600) // 1 hour
.refreshTokenValiditySeconds(2592000) // 30 days
.redirectUris("xxx")
.and()
.withClient("barClientIdPassword")
.secret(passwordEncoder().encode("secret"))
.authorizedGrantTypes("client_credentials", "refresh_token")
.scopes("bar", "read", "write")
.resourceIds("kip-apis")
.accessTokenValiditySeconds(3600) // 1 hour
.refreshTokenValiditySeconds(2592000) // 30 days
.and()
.withClient("testImplicitClientId")
.autoApprove(true)
.authorizedGrantTypes("implicit")
.scopes("read", "write", "foo", "bar")
.redirectUris("xxx");
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain
.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.authenticationManager(authenticationManager)
.tokenServices(tokenServices())
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setTokenEnhancer(accessTokenConverter());
return defaultTokenServices;
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
WebSecurityConfig:
#Configuration
#EnableWebSecurity( debug = true ) // turn off the default configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().disable() // disable form authentication
.anonymous().disable() // disable anonymous user
.authorizeRequests().anyRequest().denyAll(); // denying all access
}
#Autowired
public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("john").password(passwordEncoder.encode("123")).roles("USER").and()
.withUser("tom").password(passwordEncoder.encode("111")).roles("ADMIN").and()
.withUser("user1").password(passwordEncoder.encode("pass")).roles("USER").and()
.withUser("admin").password(passwordEncoder.encode("nimda")).roles("ADMIN");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
I have tried a few options for trying to add an additional authentication provider for the client credentials grant. Such as in the WebSecurityConfig ...
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(customDaoAuthenticationProvider);
}
It didn't work and when stepping through the authentication for client_credentials I didn't see the custom one added to the provider list, just the anonymous and dao authentication providers.
I was able to finally get the configuration of the spring security authentication server to a point where we can add multiple providers for client_credentials.
#Configuration
#EnableAuthorizationServer
public class AuthenticationServerConfig extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.addTokenEndpointAuthenticationFilter(clientCredentialsTokenEndpointFilter());
}
#Bean
protected ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter() {
ClientCredentialsTokenEndpointFilter cctef = new CustomClientCredentialsTokenEndpointFilter();
cctef.setAuthenticationManager(clientAuthenticationManager());
return cctef;
}
#Bean
protected ProviderManager clientAuthenticationManager() {
return new ProviderManager(Arrays.asList(authProvider()));
}
#Bean
protected DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new CustomDaoAuthenticationProvider();
authProvider.setUserDetailsService(clientDetailsUserService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Bean
protected BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
protected UserDetailsService clientDetailsUserService() {
return new ClientDetailsUserDetailsService(clientDetailsService());
}
#Bean
protected ClientDetailsService clientDetailsService() {
return new ClientDetailsService() {
#Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
BaseClientDetails details = new BaseClientDetails();
details.setClientId("barClientIdPassword");
details.setClientSecret(passwordEncoder().encode("secret"));
details.setAuthorizedGrantTypes(Arrays.asList("client_credentials"));
details.setScope(Arrays.asList("read", "trust"));
details.setResourceIds(Arrays.asList("kip-apis"));
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_CLIENT"));
details.setAuthorities(authorities);
details.setAccessTokenValiditySeconds(3600); //1hr
details.setRegisteredRedirectUri(null);
return details;
}
};
}
#Bean
public AuthenticationEntryPoint oauthAuthenticationEntryPoint() {
OAuth2AuthenticationEntryPoint aep = new OAuth2AuthenticationEntryPoint();
aep.setRealmName("theRealm");
return aep;
}
#Bean
public AuthenticationEntryPoint clientAuthenticationEntryPoint() {
OAuth2AuthenticationEntryPoint aep = new OAuth2AuthenticationEntryPoint();
aep.setRealmName("theRealm/client");
return aep;
}
#Bean
public AccessDeniedHandler oauthAccessDeniedHandler() {
return new OAuth2AccessDeniedHandler();
}
}
In the clientAuthenticationManager we can now add our providers to the provider manager list.
I am not sure the is the completely correct method to get this working, but it does seem to allow us to do what we wanted.

Spring social Facebook doesn't work in version 2.0.2

Hello everyone when I upgrade my application to spring version 2.0.2 I get this exception:
Description: Field connectionFactoryLocator in com.ssp.api.v1.security.SecurityConfiguration required a bean of type 'org.springframework.social.connect.ConnectionFactoryLocator' that could not be found.
here's my code:
SecurityConfiguration.java Configuration
#Configuration
#ComponentScan(basePackages = { "com.ssp.api.vi.security" })
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired private ConnectionFactoryLocator connectionFactoryLocator;
#Autowired private UsersConnectionRepository usersConnectionRepository;
#Autowired private FacebookConnectionSignup facebookConnectionSignup;
#Autowired private SspUserDetailsService sspUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/session").permitAll()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and().csrf().disable();
}
//#Autowired
#Bean
public ProviderSignInController providerSignInController() {
((InMemoryUsersConnectionRepository) usersConnectionRepository)
.setConnectionSignUp(facebookConnectionSignup);
return new ProviderSignInController(
connectionFactoryLocator,
usersConnectionRepository,
new FacebookSignInAdapter());
}
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider
= new DaoAuthenticationProvider();
authProvider.setUserDetailsService(sspUserDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
#Override
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
#Override
#Bean(name = BeanIds.USER_DETAILS_SERVICE)
public UserDetailsService userDetailsServiceBean() throws Exception { return this.sspUserDetailsService; }
AuthUtil.java Class
protected static final Logger log = LoggerFactory.getLogger(AuthUtil.class);
public static void authenticate(Connection<?> connection) {
UserProfile userProfile = connection.fetchUserProfile();
String username = userProfile.getUsername();
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
log.info("User {} {} connected.", userProfile.getFirstName(), userProfile.getLastName());
}
FacebookConnectionSignup.class Service
#Service
public class FacebookConnectionSignup implements ConnectionSignUp {
#Override
public String execute(Connection<?> connection) {
return connection.getDisplayName();
}
}
FacebookSignInAdapter.java Class
public class FacebookSignInAdapter implements SignInAdapter{
#Override
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(
connection.getDisplayName(), null,
Arrays.asList(new SimpleGrantedAuthority("FACEBOOK_USER"))
)
);
return null;
}
}
SocialConfiguration.java Configuration
#Configuration
public class SocialConfiguration {
#Bean
public SignInAdapter authSignInAdapter() {
return (userId, connection, request) -> {
AuthUtil.authenticate(connection);
return null;
};
}
}
### SspUserDetailsService.class Service
#Service
public class SspUserDetailsService implements UserDetailsService {
#Autowired private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findById(username).orElse(null);
if (user == null)
throw new UsernameNotFoundException(username);
return new SspUserDetails(user);
}
}
Console Error:
Description:
Field connectionFactoryLocator in com.ssp.api.v1.security.SecurityConfiguration required a bean of type 'org.springframework.social.connect.ConnectionFactoryLocator' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.social.connect.ConnectionFactoryLocator' in your configuration.
This code works perfectly In Spring 1.5.10 version.
How can I solve this issue?
Before of all thank you!
In Boot 2.x, you need to define the ConnectionFactoryLocator and UsersConnectionRepository in your SecurityConfiguration class, instead of autowiring them:
private ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(new FacebookConnectionFactory(appId, appSecret));
return registry;
}
private UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
return new InMemoryUsersConnectionRepository(connectionFactoryLocator);
}
Here, appId and appSecret are coming from application.properties.
You also need to change the implementation for your ProviderSignInController bean:
#Bean
public ProviderSignInController providerSignInController() {
ConnectionFactoryLocator connectionFactoryLocator = connectionFactoryLocator();
UsersConnectionRepository usersConnectionRepository = getUsersConnectionRepository(connectionFactoryLocator);
((InMemoryUsersConnectionRepository) usersConnectionRepository).setConnectionSignUp(facebookConnectionSignup);
return new ProviderSignInController(connectionFactoryLocator, usersConnectionRepository, new FacebookSignInAdapter());
}
You can find more details here.

Facing Access Denied (403) - Forbidden error in spring security oauth2

.antMatchers("/secure2/**").authenticated();
I have configured one of my api as protected, when I try to access it, It gives me Access Denied error message, I do not know what could be the reason. Note that I am passing valid access token.
My scenario:
Basically I have created logout rest api in authorization server and I want that, request with valid token is allowed to hit this api.
Request:
GET /auth/secure2 HTTP/1.1
Host: localhost:9191
Authorization: Bearer 33984141-1249-4465-a3aa-0b95a053fc63
Cache-Control: no-cache
Postman-Token: f4661790-a8e1-90ea-f6db-79cb37958cdf
Response:
{
"timestamp": 1500186837033,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/auth/secure2"
}
I found out that below method return false and due to that it raise the access denied error.
public final class ExpressionUtils {
public static boolean evaluateAsBoolean(Expression expr, EvaluationContext ctx) {
try {
return ((Boolean) expr.getValue(ctx, Boolean.class)).booleanValue();
}
catch (EvaluationException e) {
throw new IllegalArgumentException("Failed to evaluate expression '"
+ expr.getExpressionString() + "'", e);
}
}
}
Below are the screen shots which I captured by debugging in framework. Please also check the images mentioned in comment.
Code:
SecurityConfiguration.java :
import org.springframework.beans.factory.annotation.Autowired;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailService userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider
= new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
#Bean
public ShaPasswordEncoder encoder() {
return new ShaPasswordEncoder(256);
}
#Override
public void configure(WebSecurity web) throws Exception {}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
.disable()
.headers()
.frameOptions().disable().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/hello/").permitAll()
.antMatchers("/secure3/").permitAll()
.antMatchers("/oauth/token/revoke/**").authenticated()
.antMatchers("/secure2/**").authenticated();
}
#Bean
public AccessDeniedHandler accessDeniedHandler(){
return new CustomAccessDeniedHandler();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
private static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
public GlobalSecurityConfiguration() {
}
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
}
Oauth2Configuration.java
#Configuration
public class OAuth2Configuration {
#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_ACCESS_TOKEN_VALIDITY_SECONDS = "accessTokenValidityInSeconds";
private static final String PROP_REFRESH_TOKEN_VALIDITY_SECONDS = "refreshTokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
#Autowired
private DataSource dataSource;
#Autowired
private CustomUserDetailService userDetailsService;
#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())
.userDetailsService(userDetailsService)
.tokenEnhancer(tokenEnhancer())
.accessTokenConverter(accessTokenConverter())
.authenticationManager(authenticationManager);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Bean
public DefaultAccessTokenConverter accessTokenConverter() {
return new DefaultAccessTokenConverter();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("clientId")
.scopes("read", "write")
.authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_ACCESS_TOKEN_VALIDITY_SECONDS, Integer.class, 80))
.refreshTokenValiditySeconds(propertyResolver.getProperty(PROP_REFRESH_TOKEN_VALIDITY_SECONDS, Integer.class, 180))
.and().inMemory()
.withClient("clientid")
.scopes("read", "write")
.authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
.authorizedGrantTypes("client_credentials")
.secret("secret");
}
#Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
}
Controller:
#Controller
#RequestMapping("/secure2")
public class SecureController1 {
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String sayHello() {
return "Secure Hello secure2!";
}
}
What are the scenarios in which it raises access denied error message? Please let me know if any other information in needed.
I used these codes and they worked well.
OAuth2AuthorizationServerConfig.java:
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
// Configure the token store and authentication manager
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//#formatter:off
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter()) // added for JWT
.authenticationManager(authenticationManager);
//#formatter:on
}
// Configure a client store. In-memory for simplicity, but consider other
// options for real apps.
//It is not necessary.works even without this func:)
// #Override
// public void configure(AuthorizationServerSecurityConfigurer oauthServer)
// throws Exception {
// oauthServer
// .tokenKeyAccess("permitAll()")
// .checkTokenAccess("isAuthenticated()");
// }
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//#formatter:off
clients
.inMemory()
.withClient("myclient")//username in basic auth header
.secret ("{noop}123")//password in basic auth header;
.authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials", "refresh_token")
.scopes("read")
//.redirectUris("http://localhost:9191/x")
.accessTokenValiditySeconds(86400); // 24 hours
//#formatter:on
}
// A token store bean. JWT token store
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter()); // For JWT. Use in-memory, jdbc, or other if not JWT
}
// Token converter. Needed for JWT
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123"); // symmetric key
return converter;
}
// Token services. Needed for JWT
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
// #Bean
//
// public PasswordEncoder passwordEncoder () {
//
// return new BCryptPasswordEncoder();
//
// }
}
WebSecurityConfig:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
//It is not important to use this func. /oauth/token is the default path of spring security to use oauth2. she is so clever!! :)
// #Override
// protected void configure(HttpSecurity http) throws Exception {
//
//
// http.authorizeRequests()
// .antMatchers(HttpMethod.POST, "/oauth/token").permitAll()
// .anyRequest().authenticated();
// }
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}user").roles("ROLE");
}
//
// #Override
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(userDetailsService)
// .passwordEncoder(passwordEncoder());
// }
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
//
// #Bean
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
}
Output:
Please notice that the values of username and password used in code and postman, must be the same.
enter image description here
enter image description here
Hope to be helpful:)

Resources