I want to ask if it's possible to have my security configuration spread in multiple jars. For instance I have my project (myproj.war) that defines all the security rules in a #Configuration, but I also have my rest #Configuration in a separate jar(rest.jar) so people can put it in their classpath and immediately have the /rest/* support.
This all works good until the point I want to add security to the rest configuration. I add the #Configuration with the #EnableWebSecurity in my rest.jar but it doesn't get picked up! I have a breakpoint in my DigestAuthenticationFilter and it never goes through it!!! However I can see that the bean is being created during startup the filter itself is never triggered!
EDIT:
Here's my war's Security web configuration:
#Order(value = 0)
public class StorefrontWebConfig implements WebApplicationInitializer {
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
final AnnotationConfigWebApplicationContext webCtx = new AnnotationConfigWebApplicationContext();
webCtx.register(StorefrontSecurityConfig.class);
webCtx.register(StorefrontMVCConfig.class);
servletContext.addListener(new RequestContextListener());
servletContext.addListener(new HttpSessionMutexListener());
servletContext.addListener(new ContextLoaderListener(webCtx));
servletContext.addListener(new BroadcasterCreator());
/* JAWR */
.... jawr definitions ....
/* Spring Delegating Dispatcher Servlet */
final Servlet dispatcherServlet = new DispatcherServlet(webCtx);
final ServletRegistration.Dynamic dispatcherServletReg = servletContext.addServlet("dispatcherServlet", dispatcherServlet);
dispatcherServletReg.setLoadOnStartup(1);
dispatcherServletReg.setInitParameter("contextConfigLocation", "");
dispatcherServletReg.addMapping("/");
/* Character Encoding Filter */
final FilterRegistration charEncodingfilterReg = servletContext.addFilter("characterEncodingFilter", CharacterEncodingFilter.class);
charEncodingfilterReg.setInitParameter("encoding", "UTF-8");
charEncodingfilterReg.setInitParameter("forceEncoding", "true");
charEncodingfilterReg.addMappingForServletNames(null, false, dispatcherServletReg.getName());
/* Resources Filter */
final FilterRegistration resourcesFilterReg = servletContext.addFilter("resourceFilter", ResourceFilter.class);
resourcesFilterReg.addMappingForUrlPatterns(null, false, "/resources/*");
resourcesFilterReg.addMappingForUrlPatterns(null, false, "/webjars/*");
/* Storefront Delegating Filter */
final FilterRegistration storefrontFilterChainReg = servletContext.addFilter("storefrontFilterChain", DelegatingFilterProxy.class);
storefrontFilterChainReg.addMappingForServletNames(null, false, dispatcherServletReg.getName());
/* HiddenHttpMethodFilter Filter */
final FilterRegistration hiddenHttpMethodFilterReg = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);
hiddenHttpMethodFilterReg.addMappingForServletNames(null, false, dispatcherServletReg.getName());
/* Spring Security Delegating Filter */
final FilterRegistration springSecurityFilterChainReg = servletContext.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class);
springSecurityFilterChainReg.addMappingForServletNames(EnumSet.<DispatcherType>of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC), false, dispatcherServletReg.getName());
}
}
also the security configuration:
#Configuration
#EnableWebSecurity
public class StorefrontSecurityConfig {
#Autowired
private ObjectPostProcessor<Object> opp;
#Resource
public ApplicationContext context;
// #formatter:off
#Order(1)
#Configuration
public static class CheckoutStorefrontSecurityConfig extends WebSecurityConfigurerAdapter {
#Resource
public ApplicationContext context;
#Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.headers().frameOptions().disable()
.antMatcher("/checkout/**")
.anonymous().principal("anonymous").authorities("ROLE_ANONYMOUS").and()
.sessionManagement().sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy()).and()
.authorizeRequests().and()
.requiresChannel()
.antMatchers("/checkout*").requiresSecure()
.antMatchers("/checkout/**").requiresSecure()
.antMatchers("/checkout/j_spring_security_check").requiresSecure().and()
.formLogin()
.loginProcessingUrl("/checkout/j_spring_security_check").permitAll()
.loginPage("/checkout/login")
.failureHandler(defaultCheckoutAuthenticationFailureHandler())
.successHandler(defaultLoginCheckoutGUIDAuthenticationSuccessHandler()).and()
.logout()
.logoutUrl("/j_spring_security_logout")
.logoutSuccessHandler((SimpleUrlLogoutSuccessHandler) context.getBean(StoreFrontLogoutSuccessHandler.NAME)).and()
.rememberMe().rememberMeServices(context.getBean(DefaultRememberMeServices.class)).and()
.portMapper()
.http(80).mapsTo(443)
.http(8111).mapsTo(8112)
.http(8080).mapsTo(8443).and()
.exceptionHandling().accessDeniedHandler(defaultCheckoutAccessDeniedHandler()).and()
.requestCache().requestCache(httpSessionRequestCache());
}
#Bean(name = {"defaultLoginCheckoutGUIDAuthenticationSuccessHandler", "loginCheckoutGUIDAuthenticationSuccessHandler"})
protected AuthenticationSuccessHandler defaultLoginCheckoutGUIDAuthenticationSuccessHandler() {
final GUIDAuthenticationSuccessHandler guidAuthenticationSuccessHandler = new GUIDAuthenticationSuccessHandler();
guidAuthenticationSuccessHandler.setAuthenticationSuccessHandler(defaultLoginCheckoutAuthenticationSuccessHandler());
return guidAuthenticationSuccessHandler;
}
#Bean(name = {"defaultLoginCheckoutAuthenticationSuccessHandler", "loginCheckoutAuthenticationSuccessHandler"})
protected AuthenticationSuccessHandler defaultLoginCheckoutAuthenticationSuccessHandler() {
final StoreFrontAuthenticationSuccessHandler storeFrontAuthenticationSuccessHandler = new StoreFrontAuthenticationSuccessHandler();
storeFrontAuthenticationSuccessHandler.setDefaultTargetUrl("/checkout");
final Map<UiExperienceLevel, Boolean> forceDefaultTargetForUiExperienceLevel = new HashMap<UiExperienceLevel, Boolean>();
forceDefaultTargetForUiExperienceLevel.put(UiExperienceLevel.MOBILE, Boolean.TRUE);
forceDefaultTargetForUiExperienceLevel.put(UiExperienceLevel.NORMAL, Boolean.TRUE);
storeFrontAuthenticationSuccessHandler.setForceDefaultTargetForUiExperienceLevel(forceDefaultTargetForUiExperienceLevel);
return storeFrontAuthenticationSuccessHandler;
}
#Bean(name = {"defaultCheckoutAuthenticationFailureHandler", "checkoutAuthenticationFailureHandler"})
protected AuthenticationFailureHandler defaultCheckoutAuthenticationFailureHandler() {
final LoginAuthenticationFailureHandler loginAuthenticationFailureHandler = new LoginAuthenticationFailureHandler();
loginAuthenticationFailureHandler.setDefaultFailureUrl("/checkout/login?failed=auth");
return loginAuthenticationFailureHandler;
}
#Bean(name = {"defaultCheckoutAccessDeniedHandler", "checkoutAccessDeniedHandler"})
protected AccessDeniedHandler defaultCheckoutAccessDeniedHandler() {
final AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
accessDeniedHandler.setErrorPage("/403");
return accessDeniedHandler;
}
}
#Order(2)
#Configuration
public static class DefaultStorefrontSecurityConfig extends WebSecurityConfigurerAdapter {
#Resource
public ApplicationContext context;
#Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.headers().frameOptions().disable()
.anonymous().principal("anonymous").authorities("ROLE_ANONYMOUS").and()
.sessionManagement().sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy()).and()
.authorizeRequests()
.antMatchers("/my-account*").hasRole("CUSTOMERGROUP")
.antMatchers("/my-account/**").hasRole("CUSTOMERGROUP").and()
.requiresChannel()
.antMatchers("/login").requiresSecure()
.antMatchers("/login/**").requiresSecure()
.antMatchers("/register/**").requiresSecure()
.antMatchers("/signin/**").requiresSecure()
.antMatchers("/j_spring_security_check").requiresSecure()
.antMatchers("/logout").requiresSecure()
.antMatchers("/**").requiresInsecure().and()
.formLogin()
.loginProcessingUrl("/j_spring_security_check").permitAll()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/my-account", false)
.failureHandler(defaultAuthenticationFailureHandler())
.successHandler(defaultLoginGUIDAuthenticationSuccessHandler()).and()
.logout()
.logoutUrl("/j_spring_security_logout")
.logoutSuccessHandler(context.getBean(StoreFrontLogoutSuccessHandler.class)).and() .rememberMe().rememberMeServices(context.getBean(DefaultRememberMeServices.class)).and()
.portMapper()
.http(80).mapsTo(443)
.http(8111).mapsTo(8112)
.http(8080).mapsTo(8443).and()
.exceptionHandling().accessDeniedHandler(defaultAccessDeniedHandler()).and()
.requestCache().requestCache(httpSessionRequestCache());
}
#Bean(name = {"defaultLoginGUIDAuthenticationSuccessHandler", "loginGUIDAuthenticationSuccessHandler"})
protected AuthenticationSuccessHandler defaultLoginGUIDAuthenticationSuccessHandler() {
final GUIDAuthenticationSuccessHandler guidAuthenticationSuccessHandler = new GUIDAuthenticationSuccessHandler();
guidAuthenticationSuccessHandler.setAuthenticationSuccessHandler(defaultLoginAuthenticationSuccessHandler());
return guidAuthenticationSuccessHandler;
}
#Bean(name = {"defaultLoginAuthenticationSuccessHandler", "loginAuthenticationSuccessHandler"})
protected StoreFrontAuthenticationSuccessHandler defaultLoginAuthenticationSuccessHandler() {
final StoreFrontAuthenticationSuccessHandler storeFrontAuthenticationSuccessHandler = new StoreFrontAuthenticationSuccessHandler();
storeFrontAuthenticationSuccessHandler.setDefaultTargetUrl("/my-account");
storeFrontAuthenticationSuccessHandler.setUseReferer(true);
storeFrontAuthenticationSuccessHandler.setRequestCache(httpSessionRequestCache());
final Map<UiExperienceLevel, Boolean> forceDefaultTargetForUiExperienceLevel = new HashMap<UiExperienceLevel, Boolean>();
forceDefaultTargetForUiExperienceLevel.put(UiExperienceLevel.MOBILE, Boolean.TRUE);
forceDefaultTargetForUiExperienceLevel.put(UiExperienceLevel.NORMAL, Boolean.FALSE);
storeFrontAuthenticationSuccessHandler.setForceDefaultTargetForUiExperienceLevel(forceDefaultTargetForUiExperienceLevel);
return storeFrontAuthenticationSuccessHandler;
}
#Bean(name = {"defaultAuthenticationFailureHandler", "authenticationFailureHandler"})
protected AuthenticationFailureHandler defaultAuthenticationFailureHandler() {
final LoginAuthenticationFailureHandler loginAuthenticationFailureHandler = new LoginAuthenticationFailureHandler();
loginAuthenticationFailureHandler.setDefaultFailureUrl("/login?failed=auth");
return loginAuthenticationFailureHandler;
}
#Bean(name = {"defaultAccessDeniedHandler", "accessDeniedHandler"})
protected AccessDeniedHandler defaultAccessDeniedHandler() {
final AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
accessDeniedHandler.setErrorPage("/403");
return accessDeniedHandler;
}
}
#Bean(name = {"defaultAuthenticationManager", "authenticationManager"})
public AuthenticationManager defaultAuthenticationManager() throws Exception {
return new AuthenticationManagerBuilder(opp).userDetailsService(context.getBean(PlatformUserDetailsService.class)).passwordEncoder(new Md5PasswordEncoder()).and().build();
}
// #formatter:on
#Bean(name = { "defaultRedirectStrategy", "redirectStrategy" })
protected DefaultRedirectStrategy defaultRedirectStrategy() {
return new DefaultRedirectStrategy();
}
#Bean(name = { "httpSessionRequestCache", "requestCache" })
protected static HttpSessionRequestCache httpSessionRequestCache() {
return new WebHttpSessionRequestCache();
}
/* Remember-me services */
#Bean(name = { "defaultRememberMeAuthenticationFilter", "rememberMeAuthenticationFilter" })
protected RememberMeAuthenticationFilter defaultRememberMeAuthenticationFilter() throws Exception {
return new RememberMeAuthenticationFilter(defaultAuthenticationManager(), context.getBean(DefaultRememberMeServices.class));
}
#Bean(name = { "defaultRememberMeAuthenticationProvider", "rememberMeAuthenticationProvider" })
protected RememberMeAuthenticationProvider defaultRememberMeAuthenticationProvider() {
return new RememberMeAuthenticationProvider("storefront");
}
}
And then here's the REST web-config:
#Order(value = 1)
public class RestServicesWebConfig implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext webCtx = new AnnotationConfigWebApplicationContext();
webCtx.register(RestServicesSecurityConfig.class);
webCtx.register(RestServicesConfig.class);
servletContext.addListener(new RequestContextListener());
servletContext.addListener(new HttpSessionMutexListener());
/* Spring REST Delegating Dispatcher Servlet */
Servlet restDispatcherServlet = new RepositoryRestDispatcherServlet(webCtx);
ServletRegistration.Dynamic restDispatcherServletReg = servletContext.addServlet("restDispatcherServlet", restDispatcherServlet);
restDispatcherServletReg.setLoadOnStartup(1);
restDispatcherServletReg.addMapping("/rest/*");
/* Character Encoding Filter */
FilterRegistration charEncodingfilterReg = servletContext.addFilter("restCharacterEncodingFilter", CharacterEncodingFilter.class);
charEncodingfilterReg.setInitParameter("encoding", "UTF-8");
charEncodingfilterReg.setInitParameter("forceEncoding", "true");
charEncodingfilterReg.addMappingForServletNames(null, false, restDispatcherServletReg.getName());
FilterRegistration corsFilter = servletContext.addFilter("corsFilter", CorsFilter.class);
corsFilter.addMappingForUrlPatterns(null, false, "/*");
/* Spring Security Delegating Filter */
FilterRegistration springSecurityFilterChainReg = servletContext.getFilterRegistration("springSecurityFilterChain");
springSecurityFilterChainReg.addMappingForServletNames(EnumSet.<DispatcherType>of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC), false, restDispatcherServletReg.getName());
}
}
and the security config of the rest module:
#Order(3)
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class RestServicesSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ObjectPostProcessor<Object> opp;
#Resource
public ApplicationContext context;
#Resource(name = PlatformUserDetailsService.NAME)
private PlatformUserDetailsService platformUserDetailsService;
// #formatter:off
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.antMatcher("/rest/**")
.exceptionHandling()
.authenticationEntryPoint(defaultDigestAuthenticationEntryPoint()).and()
.authorizeRequests()
.anyRequest().authenticated().and()
.requiresChannel()
.antMatchers("/rest/**").requiresSecure().and()
.logout()
.logoutUrl("/logout").and()
.addFilter(defaultDigestAuthenticationFilter());
}
// #formatter:on
/* Digest authentication */
#Bean(name = { "defaultDigestAuthenticationFilter", "digestFilter" })
protected DigestAuthenticationFilter defaultDigestAuthenticationFilter() {
DigestAuthenticationFilter filter = new DigestAuthenticationFilter();
filter.setUserDetailsService(context.getBean(PlatformUserDetailsService.class));
filter.setAuthenticationEntryPoint(defaultDigestAuthenticationEntryPoint());
return filter;
}
#Bean(name = { "defaultDigestAuthenticationEntryPoint", "digestEntryPoint" })
protected DigestAuthenticationEntryPoint defaultDigestAuthenticationEntryPoint() {
DigestAuthenticationEntryPoint entryPoint = new DigestAuthenticationEntryPoint();
entryPoint.setKey("key");
entryPoint.setRealmName("Contacts Realm via Digest Authentication");
entryPoint.setNonceValiditySeconds(10);
return entryPoint;
}
#Bean(name = { "defaultRestLoginAuthenticationSuccessHandler", "restLoginAuthenticationSuccessHandler" })
protected AuthenticationSuccessHandler defaultRestLoginAuthenticationSuccessHandler() {
return new RestAuthenticationSuccessHandler();
}
#Bean(name = {"defaultAuthenticationManager", "authenticationManager"})
public AuthenticationManager defaultAuthenticationManager() throws Exception {
return new AuthenticationManagerBuilder(opp).userDetailsService(context.getBean(PlatformUserDetailsService.class)).passwordEncoder(new Md5PasswordEncoder()).and().build();
}
}
Related
I have a hard time on a personal study project. Difficulty implementing oauth2, whenever I try to get access token it returns me
2019-11-19 22:01:35.398 ERROR 4705 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError: null
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:448) ~[spring-security-config-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:449) ~[spring-security-config-5.2.0.RELEASE.jar:5.2.0.RELEASE]
2019-11-19 22:01:35.426 WARN 4705 --- [nio-8080-exec-2] o.s.web.servlet.PageNotFound : No mapping for POST /error
my project uses Version Spring Boot v2.2.0.RELEASE and Java 1.8
Application.propeties
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=test
spring.datasource.password=test123
spring.jpa.hibernate.ddl-auto=update
spring.datasource.testWhileIdle = true
spring.datasource.timeBetweenEvictionRunsMillis = 3600000
spring.datasource.validationQuery = SELECT 1
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
spring.jpa.show-sql=true
AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("angular")
.secret(passwordEncoder.encode("angular"))
.scopes("read", "write")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(1800)
.refreshTokenValiditySeconds(3600 * 24)
.and()
.withClient("admin")
.secret("admin")
.scopes("read")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(1800)
.refreshTokenValiditySeconds(3600 * 24);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter())
.reuseRefreshTokens(false)
.authenticationManager(authenticationManager);
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("financas");
return accessTokenConverter;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
ResourceServerConfig
#Configuration
#EnableWebSecurity
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/pagamento").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.csrf().disable();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.stateless(true);
}
#Bean
public static PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
public MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
SecurityConfig
#EnableWebSecurity
#EnableAuthorizationServer
#EnableResourceServer
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
}
now my refresh token classes
RefreshTokenPostProcessor
#ControllerAdvice
public class RefreshTokenPostProcessor implements ResponseBodyAdvice<OAuth2AccessToken> {
#Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return returnType.getMethod().getName().equals("postAccessToken");
}
#Override
public OAuth2AccessToken beforeBodyWrite(OAuth2AccessToken body,
MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass,
ServerHttpRequest request, ServerHttpResponse response) {
HttpServletRequest req = ((ServletServerHttpRequest)request).getServletRequest();
HttpServletResponse resp = ((ServletServerHttpResponse)response).getServletResponse();
DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) body;
String refreshToken = body.getRefreshToken().getValue();
adicionaRefreshTokenNoCookie(refreshToken, req, resp);
removerRefreshTokenDoBody(token);
return body;
}
private void removerRefreshTokenDoBody(DefaultOAuth2AccessToken token) {
token.setRefreshToken(null);
}
private void adicionaRefreshTokenNoCookie(String refreshToken, HttpServletRequest req, HttpServletResponse resp) {
Cookie refreshTokenCookie = new Cookie("refreshToken", refreshToken);
refreshTokenCookie.setHttpOnly(true);
refreshTokenCookie.setSecure(false); //TODO: change in production
refreshTokenCookie.setPath(req.getContextPath() + "/oauth/token");
refreshTokenCookie.setMaxAge(2592000);
resp.addCookie(refreshTokenCookie);
}
}
RefreshTokenPreProcessorFilter
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class RefreshTokenPreProcessorFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if ("/oauth/token".equalsIgnoreCase(req.getRequestURI())
&& "refresh_token".equals(req.getParameter("grant_type"))
&& req.getCookies() != null) {
for (Cookie cookie : req.getCookies()) {
if (cookie.getName().equals("refreshToken")) {
String refreshToken = cookie.getValue();
req = new MyServletRequestWrapper(req, refreshToken);
}
}
}
chain.doFilter(req, response);
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
static class MyServletRequestWrapper extends HttpServletRequestWrapper {
private String refreshToken;
public MyServletRequestWrapper(HttpServletRequest request, String refreshToken) {
super(request);
}
#Override
public Map<String, String[]> getParameterMap() {
ParameterMap<String, String[]> map = new ParameterMap<>(getRequest().getParameterMap());
map.put("refresh_token", new String[] {refreshToken});
map.setLocked(true);
return map;
}
}
}
SpringBootApplication
#SpringBootApplication
#WebAppConfiguration
public class FinancaApplication {
public static void main(String[] args) {
SpringApplication.run(FinancaApplication.class, args);
}
}
Remembering that my authentication is in the database and I am using PasswordEncoder on the database password and authentication passwords, I would like some help setting up the server and where my error is because I cannot generate an access token, the error returned is just this one in the console. thankful
I like your code Felipe - it's a very nicely written API - the problem is that it attempts to issue tokens also, which an API should not do.
I'd recommend walking through my tutorial, to understand the roles of API, UI and Authorization Server:
https://authguidance.com/2017/09/24/basicspa-overview/
Once you've done that I think you'll be able to adapt your API and fix your own problems - feel free to post back any follow up questions though.
In the real world almost all companies use a third party (cloud) system as the Authorization Server:
https://authguidance.com/2019/09/15/developer-domain-setup/
You will learn OAuth much faster this way - and it is free.
You then only need to focus on integrating your APIs and UIs with standards compliant endpoints like this:
https://authguidance.com/2019/03/24/java-spring-boot-api-oauth-coding/
Happy to answer follow up questions if it helps ..
As per the new requirement i have created custom UsernamePasswordAuthenticationFilter to capture additional parameters from the login page. As expected my config was working fine. I'm able to retrieve additional parameters in filter and saving to session. But after adding my custom filter to config, the session management is not working. Previous i was allowing only one session per user by setting max sessions values to 1. It is not working now, application is allowing same user to login multiple times. I'm sure that it is happening only after integrating custom UsernamePasswordAuthenticationFilter to my config. Below is my spring security config.
http.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login.html")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutSuccessUrl("/login.html")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout.html"))
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/multiplesessions.html")
.sessionRegistry(getSessionRegistry());
http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
#Bean
public SessionRegistry getSessionRegistry() {
return new SessionRegistryImpl();
}
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(dsnyUserDetailsService);
provider.setPasswordEncoder(passwordEncoder());
auth.authenticationProvider(provider);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder();
}
#Bean(name = "myAuthenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
DsnyUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter() throws Exception {
DsnyUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new DsnyUsernamePasswordAuthenticationFilter();
customUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
customUsernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login.html", "POST"));
return customUsernamePasswordAuthenticationFilter;
}
Am i missing any thing here?
I resolved this problem by adding custom ConcurrentSessionFilter. Here is the code if any one wants.
http.sessionManagement().sessionAuthenticationStrategy(concurrentSession());
http.addFilterBefore(concurrentSessionFilter(), ConcurrentSessionFilter.class);
#Bean
public CompositeSessionAuthenticationStrategy concurrentSession() {
ConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(getSessionRegistry());
concurrentAuthenticationStrategy.setMaximumSessions(1);
//concurrentAuthenticationStrategy.setExceptionIfMaximumExceeded(true);
List<SessionAuthenticationStrategy> delegateStrategies = new ArrayList<SessionAuthenticationStrategy>();
delegateStrategies.add(concurrentAuthenticationStrategy);
delegateStrategies.add(new SessionFixationProtectionStrategy());
delegateStrategies.add(new RegisterSessionAuthenticationStrategy(getSessionRegistry()));
CompositeSessionAuthenticationStrategy authenticationStrategy = new CompositeSessionAuthenticationStrategy(delegateStrategies);
return authenticationStrategy;
}
#Bean
ConcurrentSessionFilter concurrentSessionFilter() {
CustomSessionInformationExpiredStrategy redirectStrategy = new CustomSessionInformationExpiredStrategy("/pub/multiplesessions.html");
CustomConcurrentSessionFilter concurrentSessionFilter = new CustomConcurrentSessionFilter(getSessionRegistry(), redirectStrategy);
return concurrentSessionFilter;
}
CustomSessionInformationExpiredStrategy.java
public class CustomSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
private Logger log = Logger.getLogger(this.getClass().getName());
private String expiredUrl = "";
public CustomSessionInformationExpiredStrategy(String expiredUrl) {
this.expiredUrl = expiredUrl;
}
#Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException, ServletException {
log.info("Redirecting to session expired page");
HttpServletRequest request = sessionInformationExpiredEvent.getRequest();
HttpServletResponse response = sessionInformationExpiredEvent.getResponse();
request.getSession();// creates a new session
response.sendRedirect(request.getContextPath() + expiredUrl);
}
}
CustomConcurrentSessionFilter.java, no custom code here.
public class CustomConcurrentSessionFilter extends ConcurrentSessionFilter {
public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry) {
super(sessionRegistry);
}
public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry, SessionInformationExpiredStrategy sessionInformationExpiredStrategy) {
super(sessionRegistry, sessionInformationExpiredStrategy);
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
super.doFilter(req, res, chain);
}
}
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
I am developing an application which has an angular2 frontend and a spring boot backend. For the authentication I am using CAS. Single sign on is working properly, but the single log out is not working and not even redirecting to cas/logout endpoint.(I am sending a POST to my spring boot app's /logout url from angular app )
CAS version - 4.2.2
CAS client core - 3.4
I followed http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html#m3to4-filter-urls-cas and did necessary changes to Authentication Filter and Logout filter. But still I couldn't identify the issue. Any help is much appreciated.
Security Config
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private AuthProperties properties;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterBefore(requestSingleLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class)
.addFilterBefore(casAuthenticationFilter(), BasicAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(casAuthenticationEntryPoint())
.and()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("//**").authenticated()
.antMatchers("/test").permitAll()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository());
}
/***
* Service Properties refer to the application which is being authenticated
* Typically in this case, the service is the authentication engine or auth app
*/
#Bean
public ServiceProperties serviceProperties() {
ServiceProperties sp = new ServiceProperties();
sp.setService(properties.getAppServiceSecurity());
sp.setArtifactParameter("casTicket");
sp.setAuthenticateAllArtifacts(true);
sp.setSendRenew(false);
return sp;
}
#Bean
public CasAuthenticationProvider casAuthenticationProvider() throws Exception {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(userService());
casAuthenticationProvider.setServiceProperties(serviceProperties());
if (properties.isCasProxyTicket()) {
casAuthenticationProvider.setTicketValidator(cas30ServiceProxyTicketValidator());
casAuthenticationProvider.setStatelessTicketCache(ehManager());
} else {
casAuthenticationProvider.setTicketValidator(cas30ServiceTicketValidator());
}
casAuthenticationProvider.setKey(properties.getProviderKey());
return casAuthenticationProvider;
}
#Bean
public SessionAuthenticationStrategy sessionStrategy() {
SessionAuthenticationStrategy sessionStrategy = new SessionFixationProtectionStrategy();
return sessionStrategy;
}
#Bean
public Cas30ServiceTicketValidator cas30ServiceTicketValidator() {
return new Cas30ServiceTicketValidator(properties.getCasUrlPrefix());
}
#Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setSessionAuthenticationStrategy(sessionStrategy());
casAuthenticationFilter.setProxyGrantingTicketStorage(pgtStorage());
casAuthenticationFilter.setFilterProcessesUrl("/login/cas");
casAuthenticationFilter.setProxyReceptorUrl(properties.getCasProxyReceptor());
return casAuthenticationFilter;
}
#Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new TBXCasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(properties.getCasLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
#Bean
public LogoutFilter requestSingleLogoutFilter() {
StringBuffer stringBuffer = new StringBuffer("");
stringBuffer.append(properties.getCasLogoutUrl());
LogoutFilter logoutFilter = new LogoutFilter("https://localhost:9443/cas/logout", new SecurityContextLogoutHandler());//env.getRequiredProperty(CAS_URL_LOGOUT) + "?service="+ env.getRequiredProperty(APP_SERVICE_HOME)
logoutFilter.setFilterProcessesUrl("/logout");
return logoutFilter;
}
#Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter filter = new SingleSignOutFilter();
filter.setArtifactParameterName(Protocol.CAS3.getArtifactParameterName());
filter.setCasServerUrlPrefix("https://localhost:9443/cas");
filter.setIgnoreInitConfiguration(true);
return filter;
}
#Bean
public Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
if (cookie != null) {
} else {
}
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
#Bean
public CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
/**
* configure via WebSecurity provides the fonts, images, scripts, styles and views to be removed
* from the security features, because, access to these scripts is a must regarding the user experience
**/
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/fonts*//**")
.antMatchers("/images1*//**")
.antMatchers("/scripts*//**")
.antMatchers("/styles*//**")
.antMatchers("/views*//**")
.antMatchers("/i18n*//**");
}
#Bean
public UserPrincipleHandler userService() {
UserPrincipleHandler userPrincipleServiceHanlder = new UserPrincipleHandler();
return userPrincipleServiceHanlder;
}
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
#Bean
public RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
#Bean
public ServiceAuthenticationDetailsSource serviceAuthenticationDataSource() {
ServiceAuthenticationDetailsSource serviceDetailSource = new ServiceAuthenticationDetailsSource(serviceProperties());
return serviceDetailSource;
}
#Bean
public SimpleUrlAuthenticationFailureHandler simpleUrlAuthentication() {
SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
failureHandler.setDefaultFailureUrl(properties.getCasFailureUrl());
return failureHandler;
}
#Bean
public ProxyList proxyChainList() {
List<String> list = properties.getProxyList();
String[] stringArray = Arrays.copyOf(list.toArray(), list.size(), String[].class);
List<String[]> urls = new ArrayList<String[]>();
urls.add(stringArray);
ProxyList proxyList = new ProxyList(urls);
return proxyList;
}
#Bean
public ProxyGrantingTicketStorageImpl pgtStorage() {
ProxyGrantingTicketStorageImpl pgtImpl = new ProxyGrantingTicketStorageImpl();
return pgtImpl;
}
#Bean
public SpringCacheBasedTicketCache ehManager() throws Exception {
SpringCacheBasedTicketCache ehmanager = new SpringCacheBasedTicketCache(cacheMap());
return ehmanager;
}
#Bean
public ConcurrentMapCache cacheMap() {
ConcurrentMapCache conCacheMap = new ConcurrentMapCache("casTickets");
conCacheMap.put("casTickets", 50);
return conCacheMap;
}
#Bean
public Cas30ProxyTicketValidator cas30ServiceProxyTicketValidator() {
Cas30ProxyTicketValidator validator = new Cas30ProxyTicketValidator(properties.getCasUrlPrefix());//env.getRequiredProperty(CAS_URL_PREFIX)
StringBuffer stringBuffer = new StringBuffer("");
stringBuffer.append(properties.getAppServiceHome()).append(properties.getCasProxyReceptor());
validator.setProxyCallbackUrl(stringBuffer.toString());//env.getRequiredProperty(APP_SERVICE_HOME)+"login/cas/proxyreceptor"
validator.setProxyGrantingTicketStorage(pgtStorage());
validator.setAllowedProxyChains(proxyChainList());
validator.setAcceptAnyProxy(false);
return validator;
}
}
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);
}
}