Spring auth server code grant returns 401 unauthorized for endpoint /oauth2/authorize via Postman - spring

Using the spring auth server dependency 0.3.0:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.3.0</version>
</dependency>
I got these two config files:
#Configuration
#ComponentScan(basePackageClasses = AuthorizationServerConfig.class)
#Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthorizationServerConfig {
private final RegisteredClientProvider registeredClientProvider;
#Autowired
public AuthorizationServerConfig(RegisteredClientProvider registeredClientProvider) {
this.registeredClientProvider = registeredClientProvider;
}
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.formLogin(Customizer.withDefaults()).build();
}
#Bean
#ConditionalOnMissingBean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient codeClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("code-auth-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("http://127.0.0.1:8080/redirect/")
.scope("read-access")
.build();
return new InMemoryRegisteredClientRepository(codeClient);
}
}
__
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SpringSecurityConfiguration {
#Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}
I use the folloing parameters to fetch the authorization code in order to trade it for the token itself:
Unfortunately the application responses with 401 unauthorized:
GET
http://localhost:9000/oauth2/authorize?response_type=code&state=&client_id=code-auth-client&scope=read-access&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Fredirect%2F 401
I tried to fix it in the SecurityFilterChain beans but I couldn't fix it so far. Basically I am using this example https://www.baeldung.com/spring-security-oauth-auth-server (without the clients tho).
EDIT: I've noticed that the parameter "grant_type=authorization_code" was missing. Appending that parameter did not work tho.

Removing #Import(OAuth2AuthorizationServerConfiguration.class) fixed the issue.

Related

Spring Security Active Directory Authentication - infinite login pop-up

I am using Spring Boot (2.7.2) security. My security config is:
public class WebSecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated().and().httpBasic();
return http.build();
}
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
"company.com", "ldap://ldap-company.com:389");
provider.setSearchFilter("(&(objectClass=user)(sAMAccountName={0}))");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
}
Now when I hit my URI I keep getting the login pop-up infinitely.
The username and password I am providing is correct. No error(s) at the console whatsoever.
What am I doing wrong here or missing?
While I am still waiting for the right answer, I got the idea from here and it works.
So this is what I ended up with:
public class WebSecurityConfig extends GlobalAuthenticationConfigurerAdapter {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
// .fullyAuthenticated()
.and().httpBasic();
return http.build();
}
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
"ldap://ldap-company.com:389/dc=company,dc=com");
contextSource.setUserDn("CN=MYBindUser,OU=Ldap,dc=COMPANY,dc=com");
contextSource.setPassword("ComplexP#ssw0rd");
contextSource.setReferral("follow");
contextSource.afterPropertiesSet();
LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth
.ldapAuthentication();
ldapAuthenticationProviderConfigurer
.userSearchFilter("(&(cn={0}))")
// .userSearchFilter("(sAMAccountName=%s)")
.userSearchBase("")
// .groupSearchBase("(&(objectCategory=group)(cn={0}))")
.contextSource(contextSource);
}
}
Now my HTTPBasic Authentication with ActiveDirectory LDAP works just fine.

401 unauthorized page for swagger-ui

I have a problem with springfox in particular with swagger-ui. I have added this dependencies of springfox in my pom.xml:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
but when I reach swagger-ui with the url localhost:8889/app/swagger-ui.html it come back to me error 401 (my context path is '/app' and my web server start on port 8889(http)). I have also tried with the following url:
localhost:8889/app/swagger-ui
localhost:8889/swagger-ui.html
localhost:8889/swagger-ui
but the result is always the same. I have tried to reach the localhost:8889/app/v2/api-docs and this works fine (I see the json value not in human format), so swagger is working
I have configured a class of configuration for swagger in this way:
#Configuration
#EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer{
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(this.apiInfo())
.useDefaultResponseMessages(false);
}
private ApiInfo apiInfo() {
ApiInfoBuilder apiInfoBuilder = new ApiInfoBuilder();
apiInfoBuilder.title("REST API");
apiInfoBuilder.description("REST API GENERATION");
apiInfoBuilder.version("1.0.0");
apiInfoBuilder.license("GNU GENERAL PUBLIC LICENSE, Version 3");
apiInfoBuilder.licenseUrl("https://www.gnu.org/licenses/gpl-3.0.en.html");
return apiInfoBuilder.build();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/api/v2/api-docs", "/v2/api-docs");
registry.addRedirectViewController("/api/swagger-resources/configuration/ui", "/swagger-resources/configuration/ui");
registry.addRedirectViewController("/api/swagger-resources/configuration/security", "/swagger-resources/configuration/security");
registry.addRedirectViewController("/api/swagger-resources", "/swagger-resources");
}
}
I have configured also a spring security class and I have modified the configure method to ignore this request pattern:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#PropertySource(encoding = "UTF-8", value = {"classpath:commons-web-
config.properties"}, ignoreResourceNotFound = false)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Autowired
private TokenAuthenticationProvider authenticationProvider;
private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
new AntPathRequestMatcher("/public/login/login-user")
);
private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
#Override
public void configure(WebSecurity web) {
web
.ignoring()
.requestMatchers(PUBLIC_URLS);
web
.ignoring()
.antMatchers("/v2/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/public/**", "/websocket/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.sessionManagement().sessionCreationPolicy(STATELESS)
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/protected/my-controller")
.hasAnyRole("SUPER-ADMIN","ADMIN","USER")
.and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
}
#Bean
public AuthenticationEntryPoint forbiddenEntryPoint() {
return new HttpStatusEntryPoint(FORBIDDEN);
}
#Bean
public TokenAuthenticationFilter restAuthenticationFilter() throws Exception {
TokenAuthenticationFilter filter = new TokenAuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler());
return filter;
}
#Bean
public SimpleUrlAuthenticationSuccessHandler successHandler() {
SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
successHandler.setRedirectStrategy(new NoRedirectStrategy());
return successHandler;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public FilterRegistrationBean<TokenAuthenticationFilter> disableAutoRegistration(TokenAuthenticationFilter filter) {
FilterRegistrationBean<TokenAuthenticationFilter> registration = new FilterRegistrationBean<TokenAuthenticationFilter>(filter);
registration.setEnabled(false);
return registration;
}
}
I can't find the error. I believe it is in the spring security config class. Can anyone help me?
P.S. My spring boot version is 2.4.5

Swagger UI version 3 returning a 404 page but api-docs is working

I am trying to setup swagger-UI to test my springboot REST API rather than using postman however after going through a few tutorials and some questions i can not seem to get past the 404 error when trying to access the html page via my browser.
My dependencies :
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
SpringConfig:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#Configuration
#EnableSwagger2
public class SpringFoxConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
and my controller
#Controller
#CrossOrigin
#RequestMapping(path = "/api")
public class AppController {
#ResponseBody
#PostMapping(path ="/api")
public String home() {
return "Hello World";
}
#GetMapping(path = { "/api/Teacher/{id}"})
public TeacherPayload getTeacher(#PathVariable(required=false,name="id") String id) throws
Exception{
if (id != null) {
return teacher.getTeacher(id);
} else {
return teacher.getTeachers();
}
....
I changed my port number fro the default 8080 to 3005 but i do not think that should be the problem as i tried reverting back to 8080 to no avail.
Edit: My security config is as follows, note i permitted all paths to bypass the security whilst testing
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsServiceImpl jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/authenticate");
web.ignoring().antMatchers("/recoverPortal");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// We don't need CSRF for this example
httpSecurity.cors();
httpSecurity.csrf().disable()
// dont authenticate this particular request
.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "**").permitAll()
.antMatchers("/**").permitAll()
.antMatchers("/newUser").authenticated()
.antMatchers("/newUser").authenticated()
.antMatchers("/admin/**").hasAnyAuthority("USER_ADMIN")
.antMatchers("/resetPassword").authenticated()// all other requests need to be authenticated
.anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
What endpoint are you hitting? It should be /swagger-ui/ at the end, not /swagger-ui.html. Also, I think you can omit the springfox-swagger-ui dependency. All I need in my setup is the springfox-boot-starter one.

Can not get Auth login from Spring Security 5

create a simple spring security configuration on spring boot 2 m6
#Configuration
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class SecurityConfig {
#Bean
public ReactiveUserDetailsService userDetailsRepository() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("test")
.password("test")
.roles("USER")
.build();
return new MapReactiveUserDetailsService(user);
}
#Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
return http.csrf()
.disable()
.authorizeExchange()
.anyExchange().authenticated()
.and()
.httpBasic().and()
.build();
}
but when i try to get authentification object in handler request after authenfication i always get null
ReactiveSecurityContextHolder.getContext().block().getAuthentication()
and when i try to get login as
public Mono<ServerResponse> checkStatus(ServerRequest request) {
System.out.println(request.principal().block());
i also get null
where is the problem ?

Spring Boot Swagger UI - Protect UI Access

I added a simple swagger UI to my existing springboot REST API by adding the following class to my code:
#EnableSwagger2
#Configuration
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.paths(PathSelectors.regex("/v1.*"))
.build()
.pathMapping("/")
.apiInfo(metadata());
}
private ApiInfo metadata() {
return new ApiInfoBuilder()
.title("My awesome API")
.description("Some description")
.version("1.0")
.build();
}
}
My problem is that the API should be public, but the swagger docs should not. I would like a way of requesting authentication to the swagger documentation, anyone knows any simple way of achieving this?
I tried to google it but I could only find OAth stuff, but this is authentication for the endpoints not the swagger documentation...
Swagger docs will be available at /v2/api-docs endpoint when swagger integrated with spring boot application.
Inorder to protect the resource , make use of spring security and restrict the endpoint for accessing the docs
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Security configuration : restricting access to the endpoint only to the users
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/v2/api-docs").authenticated()
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
Additionally, swagger-ui.html can also be secured based on the requirement.
Here's a an alternative solution. This is about limiting access to swagger only in development/qa environment. The production environment will not have access to Swagger. I am using a property (prop.swagger.enabled) as a flag to bypass spring security authentication for swagger-ui only in development/qa environment.
#Configuration
#EnableSwagger2
public class SwaggerConfiguration extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
#Value("${prop.swagger.enabled:false}")
private boolean enableSwagger;
#Bean
public Docket SwaggerConfig() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(enableSwagger)
.select()
.apis(RequestHandlerSelectors.basePackage("com.your.controller"))
.paths(PathSelectors.any())
.build();
}
#Override
public void configure(WebSecurity web) throws Exception {
if (enableSwagger)
web.ignoring().antMatchers("/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (enableSwagger) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
}
I use this boiler plater to configure and secure swagger
#Configuration
#EnableSwagger2
public class SwaggerConfig extends WebSecurityConfigurerAdapter {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any()).build();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**")
.authenticated().and().httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
}

Resources