What is wrong with my setup? - spring-security

Recently I workmate told me our test setup not working on windows with oracle jdk.
If I enable MethodSecurityConfig below exception occurring. If I disable MethodSecurityConfig it will work fine. But method security is necessary to me.
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
How can I enable method security with #Transactional?
SecurityConfig
#Configuration
public class TestSecurityConfig {
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
#Order(value = 93)
public static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Autowired
RoleHierarchy roleHierarchy;
#Autowired
RoleVoter roleVoter;
#Autowired
AuthenticatedVoter authenticatedVoter;
#Autowired
AuthenticationManager authenticationManager;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
methodSecurityExpressionHandler.setRoleHierarchy(roleHierarchy);
return methodSecurityExpressionHandler;
}
#Override
protected AccessDecisionManager accessDecisionManager() {
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
List<AccessDecisionVoter<?>> voters = Arrays.asList(
new PreInvocationAuthorizationAdviceVoter(expressionAdvice),
roleVoter,
authenticatedVoter
);
return new AffirmativeBased(voters);
}
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return authenticationManager;
}
}
#Configuration
#EnableWebSecurity(debug = false)
#Order(94)
public static class MainSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserService userService;
#Autowired
RoleVoter roleVoter;
#Autowired
AccessDecisionManager accessDecisionManager;
#Autowired
SecurityExpressionHandler<FilterInvocation> expressionHandler;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return userService;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.accessDecisionManager(accessDecisionManager)
.expressionHandler(expressionHandler)
.anyRequest().permitAll()
;
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
AuthenticatedVoter authenticatedVoter(){
return new AuthenticatedVoter();
}
#Bean
RoleVoter roleVoter(RoleHierarchy roleHierarchy) {
return new RoleHierarchyVoter(roleHierarchy);
}
#Bean
AccessDecisionManager accessDecisionManager(AuthenticatedVoter authenticatedVoter, WebExpressionVoter webExpressionVoter, RoleVoter roleVoter) {
List<AccessDecisionVoter<?>> voters = Arrays.asList(authenticatedVoter, webExpressionVoter, roleVoter);
return new AffirmativeBased(voters);
}
#Bean
public WebExpressionVoter webExpressionVoter(SecurityExpressionHandler<FilterInvocation> webExpressionHandler) {
WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
webExpressionVoter.setExpressionHandler(webExpressionHandler);
return webExpressionVoter;
}
#Bean
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler(RoleHierarchy roleHierarchy) {
DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy);
return defaultWebSecurityExpressionHandler;
}
#Bean
public MethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) {
DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
methodSecurityExpressionHandler.setRoleHierarchy(roleHierarchy);
return methodSecurityExpressionHandler;
}
#Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
return roleHierarchy;
}
}
}
Test Case
#WebAppConfiguration
#ContextConfiguration(classes = {TestConfig.class})
#RunWith(SpringJUnit4ClassRunner.class)
public abstract class TestBase {
#Autowired
private WebApplicationContext context;
protected MockMvc mockMvc;
#Autowired
UserService userService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.addFilters(new RequestContextFilter())
.build();
}
#WithUserDetails(value = "hurelhuyag")
#Test
public void test1(){
User user = userService.loadUserByUsername("hurelhuyag");
Assert.assertNotNull(user);
Assert.assertEquals("hurelhuyag", user.getLoginname());
}
}
I full sample in github

Related

Spring Boot & Security OAuth2 Token Access issue

I have got some problem about when I wanna get "access token", I using spring security in my project
WebSecurity Config
I set user in memory for authentication in this class and I am using memory token
#Configuration
public class WebSecurityConfig {
#Bean
public static BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Configuration
#EnableWebSecurity
public static class ApiLoginConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable().csrf().disable().antMatcher("/oauth/token").authorizeRequests().anyRequest().permitAll();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("sencer").password("123").roles("ADMIN");
}
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
AuthorizationServerConfig
I define client_id and client_secret in configure(ClientDetailsServiceConfigurer configurer) for API security
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter {
static final String CLIEN_ID = "devglan-client";
static final String CLIENT_SECRET = "$2a$04$P5rlxlVjNvO2VROrwktmrevMV/XQr7LSkF6aJveL4R7k/0SAR8VQu";
static final String GRANT_TYPE = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60*60;
static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;
#Autowired
private TokenStore tokenStore;
#Autowired
#Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory()
.withClient(CLIEN_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT )
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).
refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager);
}
}
ResourceServerConfig
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource_id";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/users/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
I send grant_type , client_id , client_secret , username and password correctly but not response "access token" on API
If you want to disable basic authentication for default Token Endpoint, then preferable way is to allow form authentication for client allowFormAuthenticationForClients()
Try removing this http security configuration
http.httpBasic().disable().csrf().disable().antMatcher("/oauth/token").authorizeRequests().anyRequest().permitAll();
and configure this
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}

Does anyone have a UserDetails Service Example for Spring Cloud OAuth2 and Active Directory?

I have a Spring Cloud (Edgeware.SR3) OAuth2 Authorization server configured with Custom JWT tokens. I'm getting an IllegalStateException, UserDetailsService is required error when I hit the token_refresh endpoint.
Does anyone have an example of doing a UserDetails Service for Active Directory for this scenario? I presume the call for refreshing the token is actually checking against AD if the user is still valid such as not disabled since last successful login.
Not shown is I'm also doing integrations to AWS Cognito in the custom token enhancer which is also all working. Just the refresh token is what remains.
#Configuration
public class ServiceConfig extends GlobalAuthenticationConfigurerAdapter {
#Value("${ldap.domain}")
private String DOMAIN;
#Value("${ldap.url}")
private String URL;
#Override
public void init(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
}
--------
#Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
#Autowired
public AuthorizationServerConfiguration(AuthenticationManager authenticationManager){
super();
this.authenticationManager = authenticationManager;
}
#Value("${signing.key}")
private String signingKey;
#Bean
public JwtAccessTokenConverter accessTokenConverter(){
final JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey(signingKey);
return accessTokenConverter;
}
#Bean
public TokenStore tokenStore(){
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Primary
public DefaultTokenServices tokenServices(){
final DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
return tokenServices;
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("${client.id}")
.secret("${client.secret}")
.authorizedGrantTypes("password","refresh_token","authorization_code","client_credentials")
.refreshTokenValiditySeconds(3600 *24)
.scopes("xx","xx")
.autoApprove("xxxx")
.accessTokenValiditySeconds(3600);
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints){
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(
Arrays.asList(tokenEnhancer(),accessTokenConverter()));
endpoints
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST)
.accessTokenConverter(accessTokenConverter());
}
#Override//oauth/check_token?token={access_token}
public void configure(final AuthorizationServerSecurityConfigurer security)throws Exception {
security.checkTokenAccess("permitAll()");
super.configure(security);
}
#Bean
public TokenEnhancer tokenEnhancer(){
return new CustomTokenEnhancer();
}
}

Spring Security OAuth2 Roles Not Working

I have the below application configured
#SpringBootApplication
#EnableResourceServer
#RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#RequestMapping("/home")
public String home() {
return "Hello World";
}
#RequestMapping("/reg/a")
public String reg() {
return "REGISTERED";
}
#RequestMapping(value = "/", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public String create(#RequestBody MultiValueMap<String, String> map) {
return "OK";
}
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-client-with-secret")
.authorizedGrantTypes("client_credentials", "password")
.authorities("ROLE_CLIENT")
.scopes("read")
.resourceIds("oauth2-resource")
.secret("secret");
}
}}
and
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean(name="authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
String password = "pass";
String user = "user";
auth.inMemoryAuthentication()
.withUser(user).password(password).roles("USER")
.and().withUser("admin").password("admin").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/reg/**")
.and()
.authorizeRequests()
.antMatchers("/reg/**").access("hasRole('ADMIN')");
}
}
I am able to generate access token using below url with user/pass
http://localhost:8080/oauth/token
And later
http://localhost:8080/reg/a?access_token=bd280b8e-b0b0-47a7-96d9-b4f3bfa60692
is never blocked/thrown authorization error based on roles, I tried different ways like below, but nothing worked
hasAccess("#oauth2.hasRole('ADMIN')"), hasAuthority('ADMIIN'),
hasRole('ADMIIN')
Any help is much appreciated, thanks in advance.

Spring Boot OAuth2 with JDBC Using Custom UserDetailService

I am trying to secure my Spring Boot Rest API using OAuth2.0 with Spring security and want to store OAuth tokens (Access Token and Refresh Token) in JDBC database.
For Username and Password validation i have created CustomUserDetailService.
I am getting following error-
{
"timestamp": 1480042650103,
"status": 401,
"error": "Unauthorized",
"message": "Bad credentials",
"path": "/oauth/token"
}
My Code is -
Oauth2Config
#Configuration
#EnableAuthorizationServer
#EnableResourceServer
public class AuthorizationServerConfiguration {
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.authorizeRequests().anyRequest().authenticated();
}
}
#Configuration
#EnableAuthorizationServer
protected static class OAuth2ServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Autowired
private CustomUserDetailService customUserDetailService;
#Bean
public JdbcTokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.approvalStoreDisabled()
.userDetailsService(customUserDetailService);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.jdbc(dataSource);
}
}
}
WebSecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
CustomUserDetailService
#Service
public class CustomUserDetailService
implements UserDetailsService {
#Override
public UserDetailsService loadUserByUsername(String username) throws UsernameNotFoundException {
// I tested this logic and works fine so i avoid this lines
return userDetailsService;
}
}
application.properties
security.oauth2.client.client-id=my-trusted-client
security.oauth2.client.client-secret=secret
security.oauth2.client.authorized-grant-types=password,refresh_token,authorization_code,implicit
security.oauth2.client.scope=read,write,trust
security.oauth2.client.resource-ids=oauth2-resource
security.oauth2.client.access-token-validity-seconds=120
security.oauth2.client.refresh-token-validity-seconds=600
Please suggest me how can i solve this error ??

HTTP Status 500 - No WebApplicationContext found: no ContextLoaderListener registered?

I try use Spring MVC + Spring Data JPA + Spring Security. But my webBrowser throws exception :
"" HTTP Status 500 - No WebApplicationContext found: no ContextLoaderListener registered? java.lang.IllegalStateException:
No WebApplicationContext found: no ContextLoaderListener registered?
Here is the code:
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:252)""
public class WebInitializer implements WebApplicationInitializer{
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
FilterRegistration.Dynamic fr = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
fr.setInitParameter("encoding", "UTF-8");
fr.setInitParameter("forceEncoding", "true");
fr.addMappingForUrlPatterns(null, true, "/*");
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.register(SecurityConfig.class);
ctx.setServletContext(servletContext);
ctx.refresh();
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
servletContext
.addFilter("securityFilter",
new DelegatingFilterProxy("springSecurityFilterChain")).
addMappingForUrlPatterns(null, false, "/*");
}
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsServiceImpl userDetailsService;
#Autowired
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new PasswordEncoder() {
#Override
public boolean isPasswordValid(String arg0, String arg1, Object arg2) {
return false;
}
#Override
public String encodePassword(String arg0, Object arg1) {
return null;
}
});
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/resources/**", "/**").permitAll()
.anyRequest().permitAll()
.and();
http.formLogin()
.loginPage("/login")
.loginProcessingUrl("/j_spring_security_check")
.failureUrl("/error")
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll();
http.logout()
.permitAll()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.invalidateHttpSession(true);
}
#Bean
public ShaPasswordEncoder getShaPasswordEncoder(){
return new ShaPasswordEncoder();
}
}
#Configuration
#ComponentScan("ua.kiev.prog")
#EnableTransactionManagement
#EnableWebMvc
#EnableJpaRepositories
public class AppConfig {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory
(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter)
{
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource);
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
entityManagerFactory.setPackagesToScan("ua.kiev.prog");
return entityManagerFactory;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
return new JpaTransactionManager(emf);
}
#Bean
public JpaVendorAdapter jpaVendorAdapter()
{
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(true);
adapter.setGenerateDdl(true);
adapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
return adapter;
}
#Bean
public DataSource dataSource()
{
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/prog"); //?characterEncoding=UTF-8
ds.setUsername("root");
ds.setPassword("GFDert567");
return ds;
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
resolver.setOrder(1);
return resolver;
}
#Bean
public UserDetailsService getUserDetailsService(){
return new UserDetailsServiceImpl();
}
#Bean
public CommonsMultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
}
#SpringBootApplication
public class App {
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}

Resources