Swagger not working with spring-boot 2.7.6 - java

I use Spring Boot 2.7.6 and I tried to configure Swagger but it is not working and I do not know why. I tried to do the same configuration than the answers given for other questions related to Swagger but it does not work. I will try to give all needed information to explain my configuration.
I have this dependency in my pom.xml:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
I have these properties:
server.servlet.context-path=/my-api-web
server.port=8081
Here is my swagger configuration:
#Configuration
public class SwaggerConfig implements WebMvcConfigurer {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("com.test.api.controller")).paths(PathSelectors.any())
.build();
}
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/swagger-ui.html");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Here is my Spring security configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**")
.antMatchers(HttpMethod.OPTIONS, "/**");
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
// configure provider and filter
http.requestMatchers().antMatchers("/enpoint1/**", "/endpoint2/**").and()
.authenticationProvider(this.preAuthenticatedAuthenticationProvider())
.addFilter(this.userContextFilter());
// configure what is authenticated and what is anonymous
http.authorizeRequests().antMatchers("/endpoint1/**", "/endpoint2/**").authenticated() //
.antMatchers("/**", "/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**").permitAll() //
.anyRequest().permitAll();
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(this.authenticationEntryPoint());
}
...
}
When I try to connect to http://localhost:8081/my-api-web/v2/api-docs , I have a JSON but I also see this error in the console on back-end side:
ee4321ce-8c76-4da9-a3da-b8a86da13155 ERROR 2023-02-13 09:51:55.287 springfox.documentation.swagger2.mappers.ReferenceModelSpecificationToPropertyConverter - Unable to find a model that matches key ModelKey{qualifiedModelName=ModelName{namespace='java.lang', name='Void'}, viewDiscriminator=null, validationGroupDiscriminators=[], isResponse=true}
When I try to access to swagger-ui, it does not work. I tried https://localhost:8081/my-api-web/swagger-ui/ and http://localhost:8081/my-api-web/swagger-ui/index.html .
For the second one I have this error on front-end side:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Feb 13 09:55:12 CET 2023
There was an unexpected error (type=Not Found, status=404).
I also saw this error on back-end side but I do not know if it is linked:
java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x010x020x000x010x000x010xfc0x030x030xd2f0xbd0x130x07?L0xa99F0x0e0xfbu0xa40xae0xde'0xc370xf70xad0x990xcf0x830xe290xa30xac0x840xd60x0c0x18 ]. HTTP method names must be tokens
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:419)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:271)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
I do not know how to make swagger UI work for my case.
I also saw an answer with springdoc-openapi-ui but I do not know if it is useful for me to use swagger or if it is a replacement?

Related

How to programmatically configure keycloak with spring cloud gateway api?

I am building one spring cloud gateway and in that I am implementing Keycloak Security everything works fine but need to do programmatically instead of writing in yml file there can be multiple Realms.
Below are the dependencies which I am using:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
And my application Api gateway start application code is as below:
#SpringBootApplication
#ComponentScan(basePackages = {"com", "com.b","com.auth","com.security"})
public class APIGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(APIGatewayApplication.class, args);
}
#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new PathBasedKeycloakConfigResolver();
}
}
Security Config http code is as below:
#Configuration
public class SecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain (ServerHttpSecurity http) {
http
.authorizeExchange()
.anyExchange()
.authenticated()
.and()
.oauth2Login(); // to redirect to oauth2 login page.
return http.build();
}
}
and in my application.yml file I am adding below configuration:
spring:
security:
oauth2:
client:
provider:
my-keycloak-provider:
issuer-uri: http://localhost:8280/auth/realms/Default
registration:
keycloak-spring-gateway-client:
provider: my-keycloak-provider
client-id: Default
client-secret: 8ZRUH62Pfhfde6uqasD8dfgdhvqWt03K6
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/app'
main:
web-application-type: reactive
application:
name: app
cloud:
gateway:
default-filters:
- TokenRelay
So we can in configuration file I am manually adding configs for one Realms but there can be multiple realms in that how to do it programmatically dynamic? .

How to support multiple Spring Security authentication providers in a single application and switch between them

In my Java 11, Spring Boot 2.7.3, Maven application, I am using Spring Security in order to authenticate my users. To do this, I included the following dependency in my pom.xml file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.7.3</version>
</dependency>
And then coded the following security configuration class:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
#EnableWebSecurity
#Configuration
public class SecurityConfiguration {
#Bean
public AuthenticationProvider authenticationProvider() {
return new DocumentumAuthenticationProvider();
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/content/login")
.permitAll()
.and()
.logout()
.logoutUrl("/content/logout")
.logoutSuccessUrl("/content/logout")
.permitAll();
return http.build();
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("**/content/css/**" ,"/content/js/**" ,"/content/images/**" ,"/error/**");
}
#Bean
public BCryptPasswordEncoder encodePWD() {
return new BCryptPasswordEncoder();
}
}
Note that my custom authentication provider, DocumentumAuthenticationProvider, extends AbstractUserDetailsAuthenticationProvider. The user is prompted for credentials, which are then authenticated against a Documentum repository.
The above approach works fine.
Next, I wanted to implement SSO against Azure AD, so I removed the above security configuration class and custom authentication provider from the code set, and replaced the above pom.xml dependency with the following entries:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory</artifactId>
</dependency>
I then added the following entries to my application.properties file, using values from a new application registration that I configured after logging into my Azure AD portal:
spring.cloud.azure.active-directory.enabled=true
spring.cloud.azure.active-directory.profile.tenant-id=xxxxxxxxxxxx
spring.cloud.azure.active-directory.credential.client-id=yyyyyyyyyyyy
spring.cloud.azure.active-directory.credential.client-secret=zzzzzzzzzz
Again, this all works fine.
The goal is now to have both these authentication approaches available together in my application and to make them switchable. Not surprisingly, if I simply merge the code snippets above all together, the application will not start because I have a WebSecurityConfigurerAdapter as well as SecurityFilterChain, which is not supportable:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalStateException: Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
... 21 common frames omitted
Caused by: java.lang.IllegalStateException: Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.
Many thanks for reading. I'd be very grateful for any suggestions / guidance as to how to proceed so that I can have both authentication providers sitting side by side in my code, with the ability to switch between them with a configuration setting.

Getting "An error occurred while attempting to decode the Jwt: Couldn't retrieve remote JWK set: " error when trying to decode the jwt token

this is my Security configuration file for resource server
#Configuration
#EnableWebSecurity
public class SecureSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(STATELESS)
.and()
.authorizeRequests()
.anyRequest()
.permitAll()
.antMatchers("api/**")
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}
and those are dependencies for spring boot application (resource server app.)
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-core</artifactId>
<version>5.5.3</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
here is the jwk-set-url in the config yml file, to which my application is connecting at start up
spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: http://localhost:8083/.well-known/openid-configuration/jwks
And via postman now when I'm getting the token from auth server via postman and trying to request to my server, I'm getting this kind of error
Bearer error="invalid_token", error_description="An error occurred while attempting to decode the Jwt: Couldn't retrieve remote JWK set: org.springframework.web.client.HttpClientErrorException$NotFound: 404 null", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
who has faced such kind of issue?
Change the "Hostname Verification" to "none" in SSL properties tab.

Error creating bean with name 'springSecurityFilterChain' defined in class path resource while implementing spring security

I've been trying to implement Spring security for LDAP Authentication in Java and I'm stuck here where it's not able to find bean of 'springSecurityFilterChain'.
Following is the error -
I'm getting following error -
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'springSecurityFilterChain' defined in class
path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]:
Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method
'springSecurityFilterChain' threw exception; nested exception is java.lang.NoClassDefFoundError:
I tried to google a lot about it, got to know a few things but not sure how to implement that.
Here - https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/jc.html
it says to implement following peace of code which will register this bean in Spring but not sure where exactly to put it.
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(WebSecurityConfig.class);
}
}
Also, this is config file where I'm trying to implement Spring security
#Configuration
#EnableWebSecurity
#Import({ WebSecurityConfiguration.class })
#EnableGlobalAuthentication
#Import({ SecurityConfig.class})
public class LdapSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setAlwaysUseDefaultTargetUrl(true);
successHandler.setTargetUrlParameter("/");
http
.requiresChannel().anyRequest().requiresInsecure().and()
.authorizeRequests()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login_form")
.loginProcessingUrl("/login")
.successHandler(successHandler)
.failureUrl("/login_form?error")
.and()
.logout().logoutSuccessUrl("/login_form")
.and()
.csrf().disable();
//http.addFilterBefore(new AuthTokenFilter(authenticationManager(), userDao), BasicAuthenticationFilter.class);
http.sessionManagement().maximumSessions(2).expiredUrl("/login_form");
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
LdapAuthenticationProviderConfigurer ldapConfig =
auth.ldapAuthentication();
ldapConfig.contextSource().url("ldap://ldap.vmware.com");
ldapConfig.contextSource().managerDn("x");
ldapConfig.contextSource().managerPassword("y");
ldapConfig.userSearchFilter("(sAMAccountName={0})");
ldapConfig.userSearchBase("dc=z, dc=com");
ldapConfig.groupSearchBase(null);
TokenAuthProvider provider = new TokenAuthProvider();
auth.authenticationProvider(provider);
}
}
Please giude me through!
Have figured out the issue, here it is -
Add below file under config folder of your spring boot project, so that it will get scanned while App startup and will create bean of springSecurityFilterChain.
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Along with above code, I was missing following dpendencies too,
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
I just had following dependency for ldap authentication using spring which wasn't sufficient even after adding AbstractSecurityWebApplicationInitializer
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
Now the issue which I had posted here has resolved by following above steps.
Cheers,

Spring boot starter security not authenticating

I'm new to spring boot security and following this tutorial:
https://www.baeldung.com/spring-security-jdbc-authentication
I'm using POSTMAN to test.
I used Type = Basic Auth in Authorization -> Type
Username/Password = admin/12345
I tried everything but always get following response:
{
"timestamp": "2019-10-11T16:03:23.463+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/api/user"
}
One of the URLs:
http://localhost:8080/api/user
Here is my security configuration:
package com.spr.security;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.spr.util.Constants;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private DataSource dataSource;
#Autowired
private PasswordEncoder passwordEncoder;
protected void configure(HttpSecurity http) throws Exception
{
http.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/**").hasRole("USER")
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.csrf().disable()
.headers().frameOptions().disable();
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
{
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder);
/*
* By default spring security assumes `users` table for storing users
* and `authorities` table for storing roles
*/
}
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
Also tried:
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder());
I created following tables using entities.
users
id int AUTO_INCREMENT (PK)
username UNIQUE varchar(256)
email varchar(256)
authorities
username varchar(256)
authority varchar(256)
There is single record in each table
In users:
username = admin
password = $2y$10$llcw8Cbuww90KW1dYB6Rn.98iM0JyTiC1VBT1WveVKz99VqbhFLpG
email = abc#test.com
Password is 12345 hashed on bcrypt-generator.com with 10 strength
In authorities:
username = admin
authority = ROLE_USER
I also tried authority = USER
I have following dependency in my pom.xml
<!-- Spring data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- spring security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- for jdbc authentication -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
My application.properties file
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/sprboot?useSSL=false&serverTimezone=UTC
spring.datasource.username=spr
spring.datasource.password=boot
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=validate
spring.jackson.serialization.fail-on-empty-beans=false
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
logging.level.org.springframework.security=DEBUG
Without Spring Security, all my paths, controllers, jpa etc. works fine.
What am I doing wrong here?
Any more information required?
Edit
Is there a way to see spring security authentication sql in log window(console)
I added following in application.properties but nothing shows the generated sql
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
logging.level.org.springframework.security=DEBUG
I'm using mysql database
There were two problems and this is how I fixed:
Changed hasRole() to hasAuthority()
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/**").hasAuthority("USER")
.antMatchers("/admin/**").hasAuthority("ADMIN")
.and()
.csrf().disable()
.headers().frameOptions().disable();
}
I found in another link on stack overflow that there is a bug in Spring Security and the bcrypted password should start with $2a... and not with $2b... or $2y...

Categories

Resources