The customer want to have the following scenario:
Customer hands out link (webapp address) with 2 parameters to the webapp user. Based on these variables the user will take on specific roles in the webapp.
I don't want any authorization in it. There should only be the authentication check which looks at these url parameters and checks if they are valid and will connect the user to the appropriate role.
How can I realize this?! Is there already a solution available?
Thanks!
regards Matthias
I already solved the problem.
For those who are interested ....
web.xml
<!-- ===== SPRING CONFIG ===== -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
applicationContext.xml
<context:component-scan base-package="at.beko.rainstar2" />
<tx:annotation-driven transaction-manager="transactionManager" />
applicationContext-security.xml
<!-- Configuring security not finished!! -->
<http create-session="never" use-expressions="true" auto-config="false"
entry-point-ref="preAuthenticatedProcessingFilterEntryPoint">
<intercept-url pattern="/authError.xhtml" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" />
<session-management session-fixation-protection="none" />
</http>
<beans:bean id="userDetailsServiceImpl"
class="at.beko.rainstar2.service.impl.UserDetailsServiceImpl" />
<beans:bean id="preAuthenticatedProcessingFilterEntryPoint"
class="at.beko.rainstar2.model.LinkForbiddenEntryPoint" />
<beans:bean id="preAuthenticationProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService"
ref="userDetailsServiceImpl" />
</beans:bean>
<beans:bean id="preAuthFilter"
class="at.beko.rainstar2.service.filter.UrlParametersAuthenticationFilter">
<beans:property name="authenticationManager" ref="appControlAuthenticationManager" />
</beans:bean>
<authentication-manager alias="appControlAuthenticationManager">
<authentication-provider ref="preAuthenticationProvider" />
</authentication-manager>
LinkForbiddenEntryPoint.java
public class LinkForbiddenEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request,
HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.sendRedirect("/rainstar2-webapp/authError.xhtml");
}
}
UrlParametersAuthenticationFilter.java
public class UrlParametersAuthenticationFilter extends
AbstractPreAuthenticatedProcessingFilter {
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
if (request.getParameterMap().size() == 2) {
return true;
}
return false;
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
String[] credentials = new String[2];
credentials[0] = request.getParameter("param1");
credentials[1] = request.getParameter("param2");
return credentials;
}
}
UserDetailsServiceImpl.java
#SuppressWarnings("deprecation")
public class UserDetailsServiceImpl implements
AuthenticationUserDetailsService<Authentication> {
#Override
public UserDetails loadUserDetails(Authentication token)
throws UsernameNotFoundException {
UserDetails userDetails = null;
String[] credentials = (String[]) token.getPrincipal();
boolean principal = Boolean.valueOf(token.getCredentials().toString());
if (credentials != null && principal == true) {
String name = credentials[0];
if ("admin".equalsIgnoreCase(name)) {
userDetails = getAdminUser(name);
} else if ("händler".equalsIgnoreCase(name)) {
userDetails = getRetailerUser(name);
} else if ("user".equalsIgnoreCase(name)) {
userDetails = getUserUser(name);
}
}
if (userDetails == null) {
throw new UsernameNotFoundException("Could not load user : "
+ token.getName());
}
return userDetails;
}
private UserDetails getAdminUser(String username) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_RETAILER"));
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
return new User(username, "notused", true, true, true, true,
grantedAuthorities);
}
private UserDetails getRetailerUser(String username) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_RETAILER"));
return new User(username, "notused", true, true, true, true,
grantedAuthorities);
}
private UserDetails getUserUser(String username) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
return new User(username, "notused", true, true, true, true,
grantedAuthorities);
}
}
The way I have resolved this with similar situations is to to use a servlet filter to grab the parameters. I would recommend extending the org.springframework.web.filter.GenericFilterBean.
From these parameters, create an auth object of some sort (such as a token), that can be passed into the AuthenticationManager which you can autowire in (or get in some other method).
You will then need to have an AuthenticationProvider that can handle your auth object and generate a UserDetails object with the GrantedAuthority collection you need to satisfy the specific roles you want the user to have.
Related
I have a pretty standard implementation of spring security saml into my application in addition to other authentication mechanisms. Out of the box SAML will not be configured but can be configured through a form, so by default SAML should be disabled. I'd like to easily be able to toggle SAML on / off but am not sure what the best way to do this would be.
It seems like one approach would be to do a custom FilterChainProxy where if I check if saml is enabled and if so to ignore the samlFilter chain(How to delete one filter from default filter stack in Spring Security?) and also do a similar implementation for the Metadata Generator Filter.
Any advice would be great.
Here is my config:
<http auto-config="false" use-expressions="true"
access-decision-manager-ref="webAccessDecisionManager"
disable-url-rewriting="false"
create-session="never"
authentication-manager-ref="authenticationManager">
<custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</http>
Metadata Generator Filter:
<beans:bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<beans:constructor-arg>
<beans:bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<beans:property name="entityId" value="${saml.entityId}"/>
<beans:property name="signMetadata" value="${saml.signMetadata}"/>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
Saml Filter:
<beans:bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
<filter-chain-map request-matcher="ant">
<filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/>
<filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
<filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
<filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
<filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
<filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
<filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/>
</filter-chain-map>
</beans:bean>
EDIT: Here is my implementation, it is a bit hackish and relies on a deprecated method but it works
The below snippet disables MetadataGeneratorFilter:
public class MyMetadataGeneratorFilter extends MetadataGeneratorFilter {
private boolean isActive = false;
public MyMetadataGeneratorFilter(MetadataGenerator generator) {
super(generator);
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (isActive) {
processMetadataInitialization((HttpServletRequest) request);
}
chain.doFilter(request, response);
}
public void setActive(boolean active) {
isActive = active;
}
}
There is also the samlFilter / FilterChainMap which is autowired. If saml is enabled, I leave this chain as is, if it is disabled, I set the chain to an empty map in my service which enables / disables saml.
Upon initialization, I get the filterchainmap values:
private Map<RequestMatcher, List<Filter>> map;
#Override
public void init() throws ServiceException, MetadataProviderException {
SamlConfig samlConfig = getConfig();
map = samlFilter.getFilterChainMap();
applySamlConfig(samlConfig);
}
In the below method, I set the filter chain map to either the original map provided in the spring xml(if enabled) or an empty map (if disabled).
public void applySamlConfig(SamlConfig samlConfig) throws ServiceException, MetadataProviderException {
if (!samlConfig.isEnabled()) {
Map<RequestMatcher, List<Filter>> emptyMap = samlFilter.getFilterChainMap();
emptyMap.clear();
samlFilter.setFilterChainMap(emptyMap);
return;
}
samlFilter.setFilterChainMap(map);
i added a custom filter in the entry-point-ref definition. This filter skips all following filters if the feature is not enabled.
<security:http entry-point-ref="samlEntryPoint">
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<!-- This filter checks if the SSO-Feature is enabled - otherwise all following security filters will be skipped -->
<security:custom-filter before="BASIC_AUTH_FILTER" ref="ssoEnabledFilter"/>
<security:custom-filter before="FIRST" ref="metadataGeneratorFilter" />
<security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter" />
The ssoEnabledFilter:
public class SsoEnabledFilter extends GenericFilterBean {
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {
boolean ssoEnabled = isSsoEnabled();
if (ssoEnabled) {
filterChain.doFilter(request, response);
} else {
request.getRequestDispatcher(((HttpServletRequest) request).getServletPath()).forward(request, response);
}
}
}
So far I've been implementing this using a custom Spring namespace which includes or skips certain beans based on the backend configuration and reloading of the Spring context in case the backend configuration changes.
Edit : fixed error signaled by TheTurkish
If you want to be able to switch the use of SAML on a running application, the simpler would be to use a wrapper around samlFilter. For example
public class FilterWrapper extends GenericFilterBean {
private Filter inner;
private boolean active;
private boolean targetFilterLifeCycle = false;
public Filter getInner() {
return inner;
}
public void setInner(Filter inner) {
this.inner = inner;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
#Override
public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
if (active) {
inner.doFilter(sr, sr1, fc);
}
else {
fc.doFilter(str,sr1);
}
}
#Override
protected void initFilterBean() throws ServletException {
super.initFilterBean();
if (inner == null) {
throw new ServletException("Inner cannot be null");
}
if (targetFilterLifeCycle) {
inner.init(getFilterConfig());
}
}
#Override
public void destroy() {
super.destroy();
if (inner != null && targetFilterLifeCycle) {
inner.destroy();
}
}
}
You can use it that way :
<bean id="samlFilter" class="...FilterWrapper" p:active="false">
<property name=inner>
<!-- the real samlFilter bean -->
<bean class="org.springframework.security.web.FilterChainProxy">
...
</bean>
</property>
</bean>
As it is a bean, you inject it where you want to activate/deactivate Saml and simple call :
samlFilter.setActive(active);
I have a Spring Security configured in XML that works just fine. Now, I'm trying to have it expressed in JavaConfig only so as to get rid of the XML configuration altogether.
I've looked at the reference documentation, and at many blogs and support requests, but I still cannot find the solution.
It gives me the following exception:
Could not autowire field: private org.springframework.security.web.FilterChainProxy
com.thalasoft.learnintouch.rest.config.WebTestConfiguration.springSecurityFilterChain;
Pitifully I resorted to post my own request here...
The code:
#Configuration
#ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest" })
public class WebTestConfiguration {
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
private FilterChainProxy springSecurityFilterChain;
}
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
public class WebInit implements WebApplicationInitializer {
private static Logger logger = LoggerFactory.getLogger(WebInit.class);
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerListener(servletContext);
registerDispatcherServlet(servletContext);
registerJspServlet(servletContext);
}
private void registerListener(ServletContext servletContext) {
// Create the root application context
AnnotationConfigWebApplicationContext appContext = createContext(ApplicationConfiguration.class, WebSecurityConfiguration.class);
// Set the application display name
appContext.setDisplayName("LearnInTouch");
// Create the Spring Container shared by all servlets and filters
servletContext.addListener(new ContextLoaderListener(appContext));
}
private void registerDispatcherServlet(ServletContext servletContext) {
AnnotationConfigWebApplicationContext webApplicationContext = createContext(WebConfiguration.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(webApplicationContext));
dispatcher.setLoadOnStartup(1);
Set<String> mappingConflicts = dispatcher.addMapping("/");
if (!mappingConflicts.isEmpty()) {
for (String mappingConflict : mappingConflicts) {
logger.error("Mapping conflict: " + mappingConflict);
}
throw new IllegalStateException(
"The servlet cannot be mapped to '/'");
}
}
private void registerJspServlet(ServletContext servletContext) {
}
private AnnotationConfigWebApplicationContext createContext(final Class... modules) {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(modules);
return appContext;
}
}
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Bean
public DelegatingFilterProxy springSecurityFilterChain() {
DelegatingFilterProxy filterProxy = new DelegatingFilterProxy();
return filterProxy;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").hasRole("ROLE_ADMIN").and().httpBasic();
http.authorizeRequests().antMatchers("/admin/login", "/admin/logout", "/admin/denied").permitAll()
.antMatchers("/admin/**").hasRole("ROLE_ADMIN")
.and()
.formLogin()
.loginPage("/admin/login")
.defaultSuccessUrl("/admin/list")
.failureUrl("/admin/denied?failed=true")
.and()
.rememberMe();
http.logout().logoutUrl("/admin/logout").logoutSuccessUrl("/admin/login").deleteCookies("JSESSIONID");
}
}
The XML configuration that I hope to get rid of:
<!-- A REST authentication -->
<http use-expressions="true" pattern="/admin/**">
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
<http-basic entry-point-ref="restAuthenticationEntryPoint" />
<logout />
</http>
<!-- A form based browser authentication -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin/login" access="permitAll" />
<intercept-url pattern="/admin/logout" access="permitAll" />
<intercept-url pattern="/admin/denied" access="permitAll" />
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<form-login
login-page="/admin/login"
default-target-url="/admin/list"
authentication-failure-url="/admin/denied?failed=true"
always-use-default-target="true" />
<logout logout-success-url="/admin/login" />
<logout delete-cookies="JSESSIONID" />
</http>
<!-- A custom authentication provider on legacy data -->
<authentication-manager>
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
UPDATE:
I added a Configuration directive:
#Configuration
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
and an explicit import directive:
#Import({ SecurityWebApplicationInitializer.class })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
}
But the exception remained the exact same.
I'm running Spring Security 3.2.4.RELEASE and Spring 3.2.9.RELEASE
If you have any suggestion, it is welcomed.
I removed this bean definition from the security configuration and it seems to have solved the issue
#Bean
public DelegatingFilterProxy springSecurityFilterChain() {
DelegatingFilterProxy filterProxy = new DelegatingFilterProxy();
return filterProxy;
}
I am implementing my own authenticator provider for Spring Security 3.1.4.
But when I running application on Tomcat I receive this log error from Tomcat.
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myAppAuthenticationProvider' is defined
In web.xml y have this than others things.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml,
/WEB-INF/myapp-datasource.xml,
/WEB-INF/myapp-security.xml
</param-value>
</context-param>
<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>
In myapp-servlet.xml y have this than others things.
<!-- Activa la configuracion de beans mediante anotaciones -->
<mvc:annotation-driven />
<!-- Activa la configuracion de los controladores mediante anotaciones -->
<context:component-scan base-package="com.myapp.**" />
<!-- Activa la configuracion de seguridad mediante anotaciones -->
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />
In myapp-security.xml y have this than others things.
<security:authentication-manager alias="myAuthenticationManager">
<security:authentication-provider ref="myAppAuthenticationProvider" />
</security:authentication-manager>
Then, I have my authenticator provider like this.
#Component("myAppAuthenticationProvider")
public class MyAppAuthenticationProvider implements AuthenticationProvider {
private static final Logger Log = LoggerFactory.getLogger(AuthenticationProvider.class);
#Autowired
private UserService userService;
#Override
public final Authentication authenticate(Authentication authentication) {
final UsernamePasswordWithTypeAuthenticationToken authenticationToken =
(UsernamePasswordWithTypeAuthenticationToken) authentication;
String name = authenticationToken.getName();
String password = authenticationToken.getCredentials().toString();
String type = authenticationToken.getType();
if(isUserValid(authentication)){
List<GrantedAuthority> grantedAuth = new ArrayList<GrantedAuthority>();
grantedAuth.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuth);
return auth;
}else {
throw new BadCredentialsException("Bad authentication.");
}
}
#Override
public final boolean supports(Class<?> authentication) {
return UsernamePasswordWithTypeAuthenticationToken.class.isAssignableFrom(authentication);
}
private boolean isUserValid(Authentication authentication) {
User user = this.userService.getUserByEmailAndPassword(
authentication.getName(), authentication.getCredentials().toString());
if (user != null) {
return true;
}
return false;
}
}
Somebody can help me?, Thanks in advance.`enter code here
You have two spring contexts (first one for application beans / DS / security and second one for Spring MVC). Please make sure that your MyAppAuthenticationProvider is picked up in the first one by corresponding component-scan element. I am pretty sure that it is picked up by the second context (Spring MVC) and referenced from the first one, where it does not exist.
I am trying to perform the programmatic form based authentication and it seems that
My web.xml:
<web-app>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>confirmauthentication.xhtml</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>10</session-timeout>
</session-config>
<security-constraint>
<display-name>Authentication Ex Login</display-name>
<web-resource-collection>
<web-resource-name>SecuredArea</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>mysqldomain</realm-name>
<form-login-config>
<form-login-page>/authentication.xhtml</form-login-page>
<form-error-page>/error.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<description/>
<role-name>*</role-name>
</security-role>
</web-app>
My jsf page called authentication.xhtml:
<h:form>
<h:panelGrid border="0" columns="2">
<h:outputText value="Username"/>
<h:inputText value="#{beanJSF.userName}" required="true" />
<h:outputText value="Password"/>
<h:inputSecret value="#{beanJSF.password}" required="true" />
<h:commandButton value="Log in" action="#{beanJSF.submit}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:messages />
</h:panelGrid>
</h:form>
It seems that when I press the “Log in” button, the submit method is not called and I can’t figure out the reason. The server.log doesn’t display anything when I press the button (This message is not displayed “("I am in the login method!!!!!!!!...”).
My ManagedBean:
#URLMappings(mappings={
#URLMapping(id="success", pattern = "/authentication/", viewId = "/confirmauthentication.jsf")})
public class BeanJSF implements Serializable {
private String password;
private String userName;
// User is the Entity
private User loggedUser;
#EJB
UserEJB services;
public String submit() throws IOException {
System.out.println("I am in the login method!!!!!!!! " + getUserName()+ " " + getPassword());
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
try {
request.login(userName, password);
User user = services.authenticationUser(userName, password);
this.setLoggedUser(user);
return "home?faces-redirect-true";
} catch (ServletException e) {
// Handle unknown username/password in request.login().
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Unknown login", null));
return null;
}
}
public void logout() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath() + "/authentication.xhtml");
}
//+ setters and getters for username, password and loggedUser
}
And my EJB is:
#Stateless
public class UserEJB{
#PersistenceContext(unitName = "PyPersistenceUnit")
private EntityManager entityManager;
public UserEJB(){}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public User authenticationUser(String userName, String password){
try{
User user = entityManager.createNamedQuery(User.FIND_USER,User.class). setParameter("userName", userName).setParameter("password", password).getSingleResult();
return user;
}
catch(NonUniqueResultException ex){
ex.printStackTrace();
return null;
}
catch(NoResultException ex){
ex.printStackTrace();
return null;
}
}
Your bean is not managed by JSF and hence JSF is not able to find the bean anywhere.
Add the JSF bean management annotations to the class.
#ManagedBean
#RequestScoped
public class BeanJSF implements Serializable {
// ...
}
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);
}