Combine Spring security AUTHORIZATION bearer and CXF - spring-security

I am using Spring security + Spring core and combination with CXF for my restful.
Below are configs:
web.xml for CXF config:
<!-- Spring configuration for ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- CXF configuration for resful webservices -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
config CXF endpoint (context.xml)
<!-- configure for restful endpoint for application services as web authentication... -->
<jaxrs:server id="ApplicationServices"
address="/Application">
<jaxrs:serviceBeans>
<ref bean="ControllerImpl" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider" />
</jaxrs:providers>
<jaxrs:features>
<bean id="loggingFeature"
class="org.apache.cxf.feature.LoggingFeature">
<property name="prettyLogging" value="true" />
</bean>
<ref bean="swagger2Feature" />
</jaxrs:features>
</jaxrs:server>
spring security config - filter
public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {
AuthenticationFilter(final RequestMatcher requiresAuth) {
super(requiresAuth);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
//Optional<String> tokenParam = Optional.ofNullable(httpServletRequest.getHeader(AUTHORIZATION)); //Authorization: Bearer TOKEN
String token= StringUtils.isNotEmpty(httpServletRequest.getHeader(AUTHORIZATION))? httpServletRequest.getHeader(AUTHORIZATION) : "";
token= StringUtils.removeStart(token, "Bearer").trim();
Authentication requestAuthentication = new UsernamePasswordAuthenticationToken(token, token);
return getAuthenticationManager().authenticate(requestAuthentication);
}
#Override
protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain, final Authentication authResult) throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
}
}
spring security config - provider
#Component
public class AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
#Autowired
UserTokenService userTokenService;
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
//
}
#Override
protected UserDetails retrieveUser(String userName, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
Object token= usernamePasswordAuthenticationToken.getCredentials();
return Optional
.ofNullable(token)
.map(String::valueOf)
.flatMap(userTokenService::findByToken)
.orElseThrow(() -> new UsernameNotFoundException("Cannot find user with authentication token=" + token));
}
}
spring security config - SecurityConfiguration
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(
new AntPathRequestMatcher("/services/**"));
AuthenticationProvider provider;
public SecurityConfiguration(final AuthenticationProvider authenticationProvider) {
super();
this.provider = authenticationProvider;
}
#Override
protected void configure(final AuthenticationManagerBuilder auth) {
auth.authenticationProvider(provider);
}
/**
* we don't need provide this service for now because we are using Vaadin
*/
#Override
public void configure(final WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/token/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().exceptionHandling().and()
.authenticationProvider(provider)
.addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class).authorizeRequests()
.requestMatchers(PROTECTED_URLS).authenticated().and().csrf().disable().formLogin().disable()
.httpBasic().disable().logout().disable();
}
#Bean
AuthenticationFilter authenticationFilter() throws Exception {
final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
// filter.setAuthenticationSuccessHandler(successHandler());
return filter;
}
#Bean
AuthenticationEntryPoint forbiddenEntryPoint() {
return new HttpStatusEntryPoint(HttpStatus.FORBIDDEN);
}
}
findByToken
#Override
public Optional<User> findByToken(String token) {
UserToken userToken = userTokenDAO.findByToken(token);
if (userToken != null) {
User user = new User(userToken.getUserId(), userToken.getUserPassword(), true, true, true, true,
AuthorityUtils.createAuthorityList("USER"));
return Optional.of(user);
}
return Optional.empty();
}
However filter does not work. The request still allows comming without any validation by spring security.
The request like:
curl -X POST "http://localhost:8080/my-app/services/Application/ControllerImpl/myservice1" -H "accept: application/json" -H "Content-Type: application/json" -d "string"
There is no exception or error. The above request returns 200 (OK). I expected to fail because of no bearer token on the request.
How can we combine Spring security (using bearer token method) and CXF ?

Based on discussion in the comments, it is clear spring security filter chain is not getting configured.
Can you please add the following to your web.xml as well and see if the execution is hitting AntPathRequestMatcher matches method
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Related

Jhipster OAuth 2.0 / OIDC Authentication Authorization header with bearer token

I’ve used Jhipster to generate an app with the security option OAuth 2.0 / OIDC Authentication. I reconfigured said app to use Okta instead of keycloak following the instructions at http://www.jhipster.tech/security/#okta. All works as expected and the login flow performs as expected.
I now want to use OAuth 2.0 access_tokens to access my api resources from additional clients (Postman, Wordpress). I’ve retrieved a valid token from Okta added it to my Postman get request for localhost:8080/api/events and get a 401 in response.
The logs (https://pastebin.com/raw/R3D0GHHX) show that the spring security oauth2 doesn’t seem to be triggered by the presence of the Authorization bearer token.
Does Jhipster with OAuth 2.0 / OIDC Authentication support
access_token in the Authorization bearer header or url param out of
the box?
If not can you suggest what additional configurations I should make?
OAuth2Configuration.java
#Configuration
#Profile("dev")
public class OAuth2Configuration {
public static final String SAVED_LOGIN_ORIGIN_URI = OAuth2Configuration.class.getName() + "_SAVED_ORIGIN";
private final Logger log = LoggerFactory.getLogger(OAuth2Configuration.class);
#Bean
public FilterRegistrationBean saveLoginOriginFilter() {
Filter filter = new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
if (request.getRemoteUser() == null && request.getRequestURI().endsWith("/login")) {
String referrer = request.getHeader("referer");
if (!StringUtils.isBlank(referrer) &&
request.getSession().getAttribute(SAVED_LOGIN_ORIGIN_URI) == null) {
log.debug("Saving login origin URI: {}", referrer);
request.getSession().setAttribute(SAVED_LOGIN_ORIGIN_URI, referrer);
}
}
filterChain.doFilter(request, response);
}
};
FilterRegistrationBean bean = new FilterRegistrationBean(filter);
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
#Bean
public static DefaultRolesPrefixPostProcessor defaultRolesPrefixPostProcessor() {
return new DefaultRolesPrefixPostProcessor();
}
public static class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof FilterChainProxy) {
FilterChainProxy chains = (FilterChainProxy) bean;
for (SecurityFilterChain chain : chains.getFilterChains()) {
for (Filter filter : chain.getFilters()) {
if (filter instanceof OAuth2ClientAuthenticationProcessingFilter) {
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter =
(OAuth2ClientAuthenticationProcessingFilter) filter;
oAuth2ClientAuthenticationProcessingFilter
.setAuthenticationSuccessHandler(new OAuth2AuthenticationSuccessHandler());
}
}
}
}
return bean;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE;
}
}
}
SecurityConfiguration.java
#Configuration
#Import(SecurityProblemSupport.class)
#EnableOAuth2Sso
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
#Bean
public AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler() {
return new AjaxLogoutSuccessHandler();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**")
.antMatchers("/h2-console/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.addFilterBefore(corsFilter, CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler())
.permitAll()
.and()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/api/profile-info").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/websocket/tracker").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/websocket/**").permitAll()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/v2/api-docs/**").permitAll()
.antMatchers("/swagger-resources/configuration/ui").permitAll()
.antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN);
}
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
application.yml
security:
basic:
enabled: false
oauth2:
client:
access-token-uri: https://dev-800787.oktapreview.com/oauth2/ausb3ecnmsz8Ucjqw0h7/v1/token
user-authorization-uri: https://dev-800787.oktapreview.com/oauth2/ausb3ecnmsz8Ucjqw0h7/v1/authorize
client-id: <okta-client-id>
client-secret: <okta-client-secret>
client-authentication-scheme: form
scope: openid profile email
resource:
filter-order: 3
user-info-uri: https://dev-800787.oktapreview.com/oauth2/ausb3ecnmsz8Ucjqw0h7/v1/userinfo
token-info-uri: https://dev-800787.oktapreview.com/oauth2/ausb3ecnmsz8Ucjqw0h7/v1/introspect
prefer-token-info: false
server:
session:
cookie:
http-only: true
Matt's answer point me to the right direction, thanks!
and here is my current working configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class OAuth2AuthenticationConfiguration extends ResourceServerConfigurerAdapter {
#Bean
public RequestMatcher resources() {
return new RequestHeaderRequestMatcher("Authorization");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(resources())
.authorizeRequests()
.anyRequest().authenticated();
}
}
This answer was helpful too, thanks.
You need to use Spring Security OAuth's #EnableResourceServer for this functionality. If you're using Okta, you can also try using its Spring Boot Starter.

Swagger interacting with Resteasy not listing content api

We're trying to have Swagger interact with our resteasy app so that the api will list out on the swagger page. We're using annotations in the Java resources and not a yaml/json file. We want the content to be 'dynamic' or come directly from the resource pages.
When we bring up the swagger page, we get the message 'fetching resource list: //10.155.63.136/nodeMgmt'. When I render the page using firebug, I see that the page itself (index.html) is being 'fed in' to the content.
I think I'm pretty close but am missing one or two small things. I used the example as a guide to what I did: https://github.com/mrj365/RestEasy-3.09-Spring-3.2.5-Swagger2.0
Again, the issue is that the content from the resteasy api is not being fed into the swagger ui. The url in my case is https://10.155.63.92/nodeMgmt/index.html
We're using JBoss 6.4, NO Spring, Resteasy 3.0.7, Swagger jaxrs 1.5.9.
Any help is really appreciated.
Index.html
<script type="text/javascript">
$(function () {
window.swaggerUi = new SwaggerUi({
url: "/nodeMgmt",
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
onComplete: function(swaggerApi, swaggerUi){
log("Loaded SwaggerUI");
$('pre code').each(function(i, e) {
hljs.highlightBlock(e)
});
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: "none"
});
web.xml
<!-- Auto scan REST service -->
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/nodes</param-value>
</context-param>
<filter>
<filter-name>ApiOriginFilter</filter-name>
<filter-class>com.sonus.unity.sonusbaserestservice.utils.ApiOriginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ApiOriginFilter</filter-name>
<url-pattern>/index.html</url-pattern>
</filter-mapping>
<!-- if you are using Spring, Seam or EJB as your component model, remove the ResourceMethodSecurityInterceptor -->
<context-param>
<param-name>resteasy.resource.method-interceptors</param-name>
<param-value>
org.jboss.resteasy.core.ResourceMethodSecurityInterceptor
</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.sonus.ems.nodemgmt.web.NodeMgmtApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/nodes/*</url-pattern>
</servlet-mapping>
application.java
#ApplicationPath("")
public class NodeMgmtApplication extends SonusBaseRestApplication {
private static final Logger log = Logger.getLogger(NodeMgmtApplication.class);
/**
* Constructor
*/
public NodeMgmtApplication() {
super();
try {
//TODO Swagger
// Used for defining swagger
BeanConfig beanConfig = new BeanConfig();
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:8080");
beanConfig.setVersion("1.5.9");
beanConfig.setBasePath("/nodeMgmt");
beanConfig.setResourcePackage("com.sonus.ems.nodemgmt.web");
//beanConfig.setPrettyPrint(true);
beanConfig.setScan(true);
addService(new NodeMgmtAuthorizationFilter());
addService(new NodeMgmtRestService());
// Swagger
addService(new ApiListingResource());
addService(new SwaggerSerializers());
} catch (Exception e) {
log.error("NodeAdminApplication: Could not instantiate singletons " + e);
}
}
resource.java
#Path("/")
#Api(value = "/", description = "Node operations", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
public class NodeMgmtRestService {
private static final Logger log = Logger.getLogger(NodeMgmtRestService.class);
private static final String NODES = "nodes";
private static final String ID = "id";
NodeMgmtServiceProvider nodeMgmtServiceProvider = new NodeMgmtServiceProvider();
Service nodeMgmtService;
#GET
#Path("/{version}")
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Get all nodes", notes = "Returns a list of node", response = String.class, responseContainer="List")
public Response getNodes(
#ApiParam(value = "Version of api (1.0)", required = true) #PathParam("version") String version,
#ApiParam(value = "Filter by ", required = true) #QueryParam("filterParam") String filterParam,
#ApiParam(value = "Filter value ", required = true) #QueryParam("filterValue") String filterValue) {
List<Node> nodeList = new ArrayList<Node>();
List<Object> nodeJsonList = new ArrayList<Object>();
Map<String, List<Object>> nodeJsonMap = new HashMap<String, List<Object>>();
ObjectMapper objectMapper = new ObjectMapper();
Map<String, String> responseId = new HashMap<String, String>();
JsonNodeDao jsonNodeDao = new JsonNodeDao();
Swagger API key
public class ApiOriginFilter implements Filter {
#Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
// Add access to the header
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, OPTIONS");
res.addHeader("Access-Control-Allow-Headers", "Content-Type, api_key, Authorization");
//res.addHeader("Access-Control-Allow-Headers", "Origin, X-Atmosphere-tracking-id, X-Atmosphere-Framework, X-Cache-Date, Content-Type, api_key, Authorization, X-Atmosphere-Transport, x-requested-with, Total-Count, Total-Pages, Error-Message, *");
//res.addHeader("Access-Control-Request-Headers", "Origin, X-Atmosphere-tracking-id, X-Atmosphere-Framework, X-Cache-Date, Content-Type, api_key, Authorization, X-Atmosphere-Transport, x-requested-with, Total-Count, Total-Pages, Error-Message, *");
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}

Spring Security 3.2: JavaConfig springSecurityFilterChain setup in a Servlet <3.0 environment

I'm trying to setup Spring Security 3.2 with JavaConfig in a Servlet 2.5 environment. The reference (http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#jc) only covers the Servlet 3.0+ setup for the springSecurityFilterChain .
Grateful for hints/links how to setup this filter-chain in a Servlet 2.5 environment the right way.
Spring Security 3.2 is configured in below code with JavaConfig in Servlet 2.5 environment.
web.xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder registry)
throws Exception {
registry.userDetailsService(userDetailsService).passwordEncoder(
new BCryptPasswordEncoder());
}
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/resources");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/admin.htm")
.hasAuthority("ROLE_ADMIN")
.antMatchers("/personal/myPhotos.htm")
.hasAnyAuthority("ROLE_USER", "ROLE_FAMILY", "ROLE_ADMIN")
.antMatchers("/personal/familyPhotos.htm")
.hasAnyAuthority("ROLE_FAMILY", "ROLE_ADMIN")
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("j_username") // default is username
.passwordParameter("j_password") // default is password
.loginPage("/login.htm")
.loginProcessingUrl("/j_spring_security_check")
.failureUrl("/login.htm?login_error=t")
.permitAll()
.and()
.logout().logoutSuccessUrl("/")
.logoutUrl("/j_spring_security_logout")
.and()
.rememberMe().key("myAppKey").tokenValiditySeconds(864000);
}
}
There are some similarities and differences in javaconfig and xml configuration that are very well explained in this blog

JSF 2.0 + Spring Security 2.x

I using JSF 2.0 + Icefaces 2.0 and try to implement spring security 2.06 (not 3.x due to compatible problems with Icefaces 2.0).
I follow this guide (I think it is for JSF 1.x and Icefaces 1.8):
http://facestutorials.icefaces.org/tutorial/spring-security-basic.html
But I have problem to integrate the spring framework. I have added these lines to web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Then I have a file, applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
<security:http auto-config="true" access-denied-page="/pages/accessDenied.xhtml">
<security:intercept-url pattern="/secured/**" access="ROLE_ALLACCESS, ROLE_URLACCESS"/>
<security:form-login login-page="/pages/springSecurityLogin.xhtml"
default-target-url="/secured/welcome.xhtml"/>
<security:logout logout-success-url="/pages/logoutSuccess.xhtml"/>
</security:http>
<security:authentication-provider user-service-ref="userDetailsService"/>
<bean id="userDetailsService" class="security.UserDetailsServiceImpl">
<constructor-arg ref="userRepository"/>
</bean>
<bean id="userRepository" class="security.UserDaoImpl"/>
</beans>
The userDetailsService class is implemented according to:
package security;
import org.springframework.dao.DataAccessException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
public class UserDetailsServiceImpl implements UserDetailsService {
private UserDAO userDAO;
public UserDetailsServiceImpl(UserDAO userDAO) {
this.userDAO = userDAO;
}
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
AppUser user = userDAO.findUser(username);
if (user == null)
throw new UsernameNotFoundException("User not found: " + username);
else {
return makeUser(user);
}
}
private org.springframework.security.userdetails.User makeUser(AppUser user) {
return new org.springframework.security.userdetails.User(user.getLogin(), user
.getPassword(), true, true, true, true,
makeGrantedAuthorities(user));
}
private GrantedAuthority[] makeGrantedAuthorities(AppUser user) {
GrantedAuthority[] result = new GrantedAuthority[user.getRoles().size()];
int i = 0;
for (String role : user.getRoles()) {
result[i++] = new GrantedAuthorityImpl(role);
}
return result;
}
}
I also has a login bean:
package web.bean.security;
import org.springframework.security.ui.AbstractProcessingFilter;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
#ManagedBean(name="login")
public class Login {
// properties
private String userId;
private String password;
/**
* default empty constructor
*/
public Login() {
Exception ex = (Exception) FacesContext
.getCurrentInstance()
.getExternalContext()
.getSessionMap()
.get(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
if (ex != null)
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, ex
.getMessage(), ex.getMessage()));
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void login(ActionEvent e) throws java.io.IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect("/spring-authentication/j_spring_security_check?j_username=" + userId + "&j_password=" + password);
}
}
The problem is when I running a jsf file which using the login bean:
The requested resource () is not available.
I'm using Tomcat 7.
Can you please help me?
Best Regards /kungcc
I think you need to add the webapplication name before the /j_spring_security_check
like /WebAppName/j_spring_security_check that will aply the spring on all what comes after /webAppName
Does omitting /spring-authentication in the login() method of login bean help?
public void login(ActionEvent e) throws java.io.IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect("/j_spring_security_check?j_username=" + userId + "&j_password=" + password);
}

Get original request url in Spring Security form-login page

I have the following declared in my spring security configuration file (http://www.springframework.org/schema/security/spring-security-2.0.1.xsd):
<form-login login-page="/login.html" />
What Spring Security does is redirect the user to that page if they don't have the correct authentication credentials. How can I get the url of the page the user was trying to get to?
Original request is represented by the SavedRequest object, which can be accessed as a session attribute named SPRING_SECURITY_SAVED_REQUEST_KEY.
in my case i did something like this and it worked for me.
#Autowired
private LoggedUserListener loggedUserListener;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/find/**","/","/Application/**")
.access("hasRole('ROLE_USER')")
.successHandler(loggedUserListener)
//some other stuff
}
#Component
public class LoggedUserListener implements AuthenticationSuccessHandler{
#Autowired
private UserRepo userRepo;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
HttpSession session = request.getSession();
SavedRequest savedRequest = (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
if(savedRequest != null) {
User u = userRepo.findByUsername(authentication.getName());
u.setLastLogin(new Date());
u.setAccountNonLocked(false);
userRepo.save(u);
response.sendRedirect(savedRequest.getRedirectUrl());
}
}
}
In Spring Security 4
The original request is represented by the DefaultSavedRequest object, which can be accessed as a session attribute named SPRING_SECURITY_SAVED_REQUEST.
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(HttpSession session) {
DefaultSavedRequest savedRequest = (DefaultSavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
}

Resources