Unable to make swagger doc ui/api public in spring boot security - spring

I am trying to add swagger to my existing application. I have added the following dependencies :
<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>
Now the API /swagger-ui/ and /v2/api-docs is working fine. I am developing the application in REST API. The API's are working fine from POST man when i am sending JWT Token with them. They are not working in browser.
To make them working in browser, i have added the URL's in spring security permit all. But it is still not working in browser.
Spring Security Config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(
.............
"/v2/api-docs",
"/swagger-ui.html")
.permitAll().anyRequest().authenticated().and().addFilter(getAuthenticationFilter())
.addFilter(new AuthorizationFilter(authenticationManager())).sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().cors();
}
How can i make those API's public?

try using security config
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_WHITELIST = {
"/healthz"
};
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(AUTH_WHITELIST);
}
}

You need to make public more urls than just those two.
Springfox documentation states to allow the following urls
.antMatchers(
HttpMethod.GET,
"/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html**",
"/webjars/**",
"favicon.ico"
).permitAll()
or to ignore them:
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html**",
"/webjars/**");
}
}
source: https://springfox.github.io/springfox/docs/current/

Related

new Authorization Server Custom Login Page

I am using new Spring Authorization Server
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.3</version>
</dependency>
I wan to configure custom login page. I have two beans configured
AuthorizationServerConfig.java
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.cors(Customizer.withDefaults())
.formLogin()
.and().build();
}
SecurityConfig.java
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.authorizeRequests(authorizeRequests ->
authorizeRequests.mvcMatchers("/custom-login", "/css/**", "/js**", "/image/**").permitAll().anyRequest().authenticated()
)
.formLogin()
.loginPage("/custom-login").failureForwardUrl("/custom-login?error");
return http.build();
}
Whenever User enter incorrect credentials is not being directed to /custom-login?error
He is directed to /custom-login
I seems .failureForwardUrl("/custom-login?error"); is not working
If don't use custom login page user is being directed to /login?error=some-error
Can someone help to solve this problem?
I solved the problem.
I changed the configuration to
AuthorizationServerCOnfig.java
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http
.cors(Customizer.withDefaults())
.formLogin().loginPage("/custom-login").failureForwardUrl("/custom-login?error=true")
.and()
.build();
}
SecurityConfig.java
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.formLogin().failureForwardUrl("/custom-login")
return http.build();
}
I added LoginController.java to handle custom-login redirects.
#Controller
public class LoginController {
#GetMapping("/custom-login")
public String login() {
return "login";
}
#PostMapping("/custom-login")
public String loginFailed() {
return "redirect:/authenticate?error=invalid username or password";
}
}
If you don't specify those end points. you will be redirected to /login
Also I had both
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
And
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.3</version>
</dependency>
My service was both authorization server and resource server at the same time.
So I removed
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
And every thing works expectedly

Spring Boot Security Authentication: Application having 2 different domain URL and need to authenticate with Spring Security

I need help with one of the issue that I am facing with Spring Boot Security. I have application which has 2 different Urls.(Infoblock CNAME)
domain1.com
domain2.com
both Url are point to the same application.
Due to business reason we need 2 different Url and we are planning to land on diff page based on the URL entered in browser. Issue is with Spring Security AntMatcher.
With AntMatcher we can only provide path but how we can address the domain with it.
Could you please guide me.
Thanks in Advance.
Instead of AntMatcher you can use
http.requestMatcher(new RequestHeaderRequestMatcher("Host", "127.0.0.1:8080"))
with any other matcher from org.springframework.security.web.util.matcher package.
Here is an example:
#EnableWebSecurity
#Configuration
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Configuration
#Order(1)
public static class SecConfig1 extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new RequestHeaderRequestMatcher("Host", "127.0.0.1:8080"))
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin();
}
}
#Configuration
#Order(2)
public static class SecConfig2 extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new RequestHeaderRequestMatcher("Host", "127.0.0.2:8080"))
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
//default deny all
http.authorizeRequests().anyRequest().denyAll();
}
}

Spring Keycloak Bearer only

Iam developing a angular webapp which is connected to a java (spring framework) backend. Authentication is done via a keycloak server.
On my local machine with the embedded tomcat server the angular application and the spring application runs without errors.
For deployment i need to use the old fashioned way by using an existing tomcat server.
The angular frontend is available in the ROOT directory via http://myurl/
The spring backend is placed as war file and reachable via http://myurl/api/
Everything works on the server except the authentication part.
Angular app is able to login via redirect etc. and gets an access token.
This token is transmitted on a request to the spring backend.
But the backend return a not authorized message.
Any help is apriciated!
Message is:
Unable to authenticate using the Authorization header
I have created a SecurityConfig class:
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(
AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider
= keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/*")
.authenticated()
.anyRequest()
.permitAll();
}
}
Added this line to the application properties
keycloak
keycloak.auth-server-url=https://authserver.net/auth
keycloak.realm=myRealm keycloak.bearer-only=true
keycloak.resource=myclient
keycloak.cors=true
And added this dependancies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>3.3.0.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Disabling the csrf token solved this issue.
Example:
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/*")
.authenticated()
.anyRequest()

OAuth2AccessToken not set in Oauth2ClientContext after login

I'm having some difficulties to get client token relay working with Spring Boot 2.0.0.M7 and Spring Cloud Finchley M5. Please find the example code on github: https://github.com/hansvanbeneden/oauth-example
I have configured the oauth2Login like this:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.and()
.csrf().disable();
}
}
and the client registration repo like this:
#Configuration
#EnableOAuth2Client
public class OAuth2LoginConfig {
#Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.myWebsiteClientRegistration());
}
private ClientRegistration myWebsiteClientRegistration() {
return ClientRegistration
.withRegistrationId("myauth")
...
.build();
}
#Bean
public OAuth2RestOperations restOperations(OAuth2ClientContext oauth2ClientContext) {
return new OAuth2RestTemplate(resource(), oauth2ClientContext);
}
private OAuth2ProtectedResourceDetails resource() {
ClientRegistration myauthClient = myWebsiteClientRegistration();
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setScope(new ArrayList<>(myauthClient.getScopes()));
...
return resource;
}
}
I would expect that the oauth2Login somehow sets the OAuth2AccessToken in the Oauth2ClientContext for the OAuth2RestTemplate to use it. But apparently this is not the case, because a UserRedirectRequiredException is thrown when I use the OAuth2RestTemplate.
Is there some magic annotation that I'm missing?
Can someone please send me in the right direction?
Please feel free to correct me if i'm wrong, but basically this is how I understand the issue:
Spring Boot 2.0 dropped support for spring-security-oauth2, since it now has it's own OAuth support (documented here: https://docs.spring.io/spring-security/site/docs/5.0.0.BUILD-SNAPSHOT/reference/htmlsingle/#jc-oauth2login)
This means you can't use the new oauth2Login configuration and expect the Oauth2RestTemplate to be able to use the oauth tokens set by oauth2Login
The following project was setup to allow the use of spring-security-oauth2 features in Spring Boot 2.0: https://docs.spring.io/spring-security-oauth2-boot/docs/current-SNAPSHOT/reference/htmlsingle/
To solve my issue I added the spring-security-oauth2-autoconfigure dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</dependency>
I removed the oauth2Login and added the EnableOauth2Ssso from the WebSecurityConfig:
#Configuration
#EnableOAuth2Sso
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.csrf().disable();
}
}
Then my Oauth2RestTemplate was able to find the OAuthToken that was acquired by logging in.
#Bean
public RestOperations restOperations(OAuth2ProtectedResourceDetails resourceDetails,
OAuth2ClientContext clientContext) {
return new OAuth2RestTemplate(resourceDetails, clientContext);
}
I have committed this solution on the following branch: https://github.com/hansvanbeneden/oauth-example/tree/implementation-with-spring-security-oauth2-boot

Spring Boot Management security works differently with port set

I'm trying to configure a Spring Boot application (1.2.3, but this also fails with the 1.2.4.BUILD-SNAPSHOT version) with Actuator support. I want to use the Actuator security config for controlling access to the management endpoints, and our own authentication for the rest of the application.
Here is my security config:
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
#Autowired
private CustomAuthenticationProvider customAuthProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(customAuthProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.regexMatchers(API_DOC_REGEX).permitAll()
.regexMatchers(String.format(PATH_REGEX, PUBLIC_ACCESS)).permitAll()
.regexMatchers(String.format(PATH_REGEX, INTERNAL_ACCESS)).access("isAuthenticated() && authentication.hasOrigin('INTERNAL')")
.regexMatchers(String.format(PATH_REGEX, EXTERNAL_AUTHENTICATED_ACCESS)).authenticated()
.antMatchers("/**").denyAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
.addFilterAfter(customAuthProcessingFilter(), BasicAuthenticationFilter.class)
.csrf().disable();
}
}
This works correctly when I don't set a management port, but when I set the management port, the management URLs return 401 responses. If I comment out the line .antMatchers("/**").denyAll(), then everything goes through without requiring authentication at all. So it looks like it is using my application's security config for the Actuator endpoints when I set a custom port, but I'm not sure why.
How do I get it to use it's own security when running on a custom port?
Expanding on the comment from #M. Deinum, adding another adapter for the Management stuff (even though it already has one) seems to have fixed it. This is the class I ended up with:
#Order(0)
#Configuration
public class ManagementSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
ManagementServerProperties managementProperties;
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.requestMatchers()
.requestMatchers(new RequestMatcher()
{
#Override
public boolean matches(HttpServletRequest request)
{
return managementProperties.getContextPath().equals(request.getContextPath());
}
})
.and()
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}

Resources