I have a Java EE EAR Application running on wildfly 8.2,I am trying to implement Java EE declarative security to protect access to the EJB methods. Thus, I have added to the standalone.xml
<security-domain name="MyDomain" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:jboss/datasources/MyDatasource"/>
<module-option name="principalsQuery" value="select password from user where username = ?"/>
<module-option name="rolesQuery" value="select DISTINCT r.name, 'Roles' from role r left join user_roles ur on ur.role_id=r.id left join user u on u.id=ur.user_id where u.username= ? and u.status=1 and r.active=1"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="base64"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
</authentication>
</security-domain>
In jboss-web.xml I have
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
<security-domain>MyDomain</security-domain>
<disable-audit>true</disable-audit>
<context-root/>
</jboss-web>
and in web.xml I have
<login-config>
<auth-method>FORM</auth-method>
<realm-name>MyDomain</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/login.xhtml?failed=true</form-error-page>
</form-login-config>
</login-config>
In one of the ManagedBeans I have
#Named("levelController")
#DeclareRoles({"Create-Level", "View-Level", "Edit-Level", "Delete-Level"})
public class LevelController implements Serializable {
#DenyAll
public String create() {
//bla bla bla
}
}
I accessed the levelController.create() from the jsf and was able to create Level successfully without logging in.
This simply implies that the security annotation is NOT working/maybe there is something I am not doing right. Can someone please help me spot out what the issue is
#DenyAll and #DeclareRoles (as well as #RolesAllowed) only work with EJB (session) beans, not with beans that are just named.
Try adding #Stateless to make your bean a session bean, or #Stateful in combination with a scope (eg #RequestScoped).
Related
I have a demo JAX-RS project using Jersey. Now I am trying add Spring Security's method level security but unfortunately its not working although intercept-url xml way is working fine.
Added all the dependency in my pom.xml
Updating web.xml as
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/security.xml,
/WEB-INF/beans.xml
</param-value>
</context-param>
<!-- this is default security impl name used by deletetingFiterProxy -->
<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>
Updating /WEB-INF/security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- kind of authentication applied 1) Basic 2) form-based etc.. auto-config="true" use-expressions="true"-->
<http auto-config="true">
<http-basic />
</http>
<!-- this allow to enable security annotations in restful resoruces -->
<global-method-security secured-annotations="enabled" />
<!-- for defining users and roles -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_CUSTOMER,ROLE_ADMIN"/>
<user name="student" password="student" authorities="ROLE_CUSTOMER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Annotating service inteface methods
public interface StudentServiceInterface {
#GET
#Path("/students")
#Secured("ROLE_CUSTOMER")
public Response getStudents();
#GET
#Path("/students/{id}")
#Secured("ROLE_CUSTOMER")
public Response getStudent(#PathParam("id") int id);
#POST
#Path("/students")
#Consumes(MediaType.APPLICATION_JSON)
#Secured("ROLE_ADMIN")
public Response addStudent(Student stu);
}
Now when I try to access the resource student (/student) class it opens without asking password.
http://localhost:3126/securitydemo/webapi/db/students
StudentServiceInterface interface implementation
#Path("/db")
#Produces(MediaType.APPLICATION_JSON)
public class StudentService implements StudentServiceInterface{
static StudentDao data= new StudentDaoImpl();
#Override
public Response getStudents(){
GenericEntity<List<Student>> entity = new GenericEntity<List<Student>>(data.getAllStudents()){};
return Response.ok(entity).build();
}
#Override
public Response getStudent(#PathParam("id") int id){
return Response.ok(data.getStudent(id)).build();
}
#Override
public Response addStudent(Student stu) {
data.addStudent(stu);
return Response.ok(stu).build();
}
}
You have to use the extention for Spring DI, see Jersey 2.25.1 User Guide:
Jersey provides an extension to support Spring DI. This enables Jersey to use Spring beans as JAX-RS components (e.g. resources and providers) and also allows Spring to inject into Jersey managed components.
The Spring extension module configuration is based on annotations. Spring beans are injected and JAX-RS classes are made Spring managed using annotations. Injected Spring beans can have further dependencies injected using Spring XML configuration. Spring singleton and request scopes are supported.
To enable JAX-RS resources to work Spring functionality that requires proxying, such as Spring transaction management (with #Transactional), Spring Security and aspect oriented programming (such as #Aspect), the resources must themselves be managed by Spring, by annotating with #Component, #Service, #Controller or #Repository:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.springframework.stereotype.Component;
#Component
#Path("/")
public class SomeResource {
#Transactional
#GET
public void updateResource() {
// ...
}
}
Limitations:
Spring beans can't be injected directly into JAX-RS classes by using Spring XML configuration
25.1. Dependencies
If you want to use Jersey Spring DI support you will need to add the jersey-spring3 module into the list of your dependencies:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.25.1</version>
</dependency>
The above module adds transitive dependencies on Spring modules. See jersey-spring3 module dependencies for more details about list and scope of dependencies. Please note the module depends on The Spring/HK2 Bridge that is used to inject Spring services into HK2 services or inject HK2 services into Spring services.
I'm upgrading from Spring Security 3.2.5 to 4.0.4, working with the migration guide.
My UserDetailsService looks like this:
package com.me.security;
import org.springframework.security.core.userdetails.UserDetailsService;
public class Users implements UserDetailsService {
public Users() {
System.err.println("USERS CONSTRUCTOR");
}
#Override
public UserDetail loadUserByUsername(String name) {
System.err.println("LOAD BY USER NAME " + name);
throw new UsernameNotFoundException("User not found.");
}
}
My WEB-INF/applicationContext.xml has this:
<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-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<security:http disable-url-rewriting="true" use-expressions="false">
<security:intercept-url pattern="/auth/**" access="ROLE_ANONYMOUS"/>
<security:intercept-url pattern="/dashboard/**" access="ROLE_ADMIN,ROLE_USER"/>
<!-- ...more intercept-urls... -->
<security:access-denied-handler error-page="/pages/general/403.xhtml"/>
<security:form-login login-page="/auth/login.html"
username-parameter="j_username"
password-parameter="j_password"
login-processing-url="/j_spring_security_check"
default-target-url="/dashboard/"
authentication-failure-url="/auth/error.html"/>
<security:logout logout-success-url="/auth/login.html"
logout-url="/auth/login.html"
delete-cookies="JSESSIONID"
invalidate-session="true" />
<security:session-management invalid-session-url="/auth/login.html"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref='userDetailsService'/>
</security:authentication-manager>
<bean id="userDetailsService" class="com.me.security.Users"/>
</beans>
When I try to log in, my code does not get called. I do see the message from the Users constructor in the server logs, but not the one from its loadUserByUsername method.
Instead, no matter what I enter for user name and password, I get to my 403 error page.
(Maybe I've been looking at this for too long already...)
Why doesn't Spring call my UserDetailsService and what do I need to get it to work?
It sounds to be the csrf filter. In Spring Security 4.x it is activated by default: Migrating from Spring Security 3.x to 4.x. This may be problem if you are allways getting an HTTP 403.
Try disabling setting this inside the security:http element:
<csrf disabled="true"/>
I'm using Spring 4.1.5 and Spring Security 4.0.0.RELEASE.
I read http://spring.io/blog/2014/05/07/preview-spring-security-test-method-security (nice article by Rob Winch) and developed my own implementation of WithSecurityContextFactory to be able to test my Spring MVC controllers:
public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {
#Override
public SecurityContext createSecurityContext(WithMockCustomUser customUser) {
final User fakeUser = new User();
final SecurityUser principal = new SecurityUser(fakeUser);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, "password", HelpersTest.getAuthorities(customUser.faps()));
final SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(auth);
return context;
}
}
My abstract resource test class is as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations =
{
"classpath:spring/mock-daos-and-scan-for-services.xml",
"classpath:security.xml",
"classpath:singletons.xml",
"classpath:controller-scan.xml",
"classpath:servlet.xml" })
#TestExecutionListeners(listeners=
{
ServletTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
WithSecurityContextTestExcecutionListener.class })
public abstract class AbstractResourceMockMvcTest {
#Autowired
private WebApplicationContext wac;
#Autowired
private Filter springSecurityFilterChain;
private MockMvc mockMvc;
[...]
#Before
public void setup() {
this.mockMvc =
MockMvcBuilders.webAppContextSetup(this.getWac())
.addFilters(springSecurityFilterChain)
.build();
}
[...]
}
Then, my concrete test class inherits from AbstractResourceTest (from above) and it uses the following annotation on a #Test-enabled method:
#WithMockCustomUser(faps={"promotion_read"})
Tracing the code, I can confirm WithMockCustomUserSecurityContextFactory.createSecurityContext() is called and its return value is set in SecurityContextHolder.setContext() (through TestSecurityContextHolder.setContext()).
So far, so good !
However, later in the process, SecurityContextPersistenceFilter.doFilter() calls SecurityContextHolder.setContext() and this overwrites the context set by the test and I lose track of the mocked security context I prepared.
security.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
"
>
<!-- HTTP security handling -->
<security:http use-expressions="true">
<security:logout logout-url="/j_spring_security_logout" invalidate-session="true" logout-success-url="/login.jsp?loggedout=true" />
<security:custom-filter before="FIRST" ref="multiTenantRequestFilter" />
<!-- make sure following page are not secured -->
<security:intercept-url pattern="/*/*/internal/**" access="hasIpAddress('127.0.0.1')" />
<!-- make sure everything else going through the security filter is secured -->
<security:intercept-url pattern="/resources/**" access="hasRole('ROLE_USER')" requires-channel="any" />
<!-- supporting basic authentication for unattended connections (web services) -->
<security:http-basic />
</security:http>
<!-- authentication strategy -->
<security:authentication-manager alias="authManager">
<security:authentication-provider user-service-ref="userSecurityService">
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
<!-- custom filter to intercept the tenant name from the login form -->
<bean id="multiTenantRequestFilter" class="com.meicpg.ti.web.MultiTenantRequestFilter" />
</beans>
servlet.xml:
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
"
>
<mvc:annotation-driven>
<!-- Content skipped for StackOverflow question -->
</mvc:annotation-driven>
<context:annotation-config />
<bean id="annotationExceptionResolver" class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<security:global-method-security pre-post-annotations="enabled"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
How can I prevent this security context overwrite ? Does my security.xml contain an obvious flaw I missed ?
PS: I skipped the other context configuration files as they seem irrelevant to the problem.
Thanks in advance !
Unfortunately that blog post is just for method level security and does not have complete instructions for MockMvc setup (the following blog in the series does). Additionally, the blogs are actually dated (I have updated them to reflect that readers should refer to the reference documentation). You can find updated instructions in the Testing Section of the reference.
In short, update your code to the following:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations =
{
"classpath:spring/mock-daos-and-scan-for-services.xml",
"classpath:security.xml",
"classpath:singletons.xml",
"classpath:controller-scan.xml",
"classpath:servlet.xml" })
public abstract class AbstractResourceMockMvcTest {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
[...]
#Before
public void setup() {
this.mockMvc =
MockMvcBuilders.webAppContextSetup(this.getWac())
.apply(springSecurity())
.build();
}
#Test
#WithMockCustomUser(faps={"promotion_read"})
public void myTest() {
...
}
[...]
}
A few highlights:
You no longer need to provide the TestExecutionListeners
Use .apply(springSecurity()) instead of adding the spring security filter chain manually
This works because Spring Security's test support i.e. apply(springSecurity()) will override the SecurityContextRepository used by the springSecurityFilterChain to first try the TestSecurityContextHolder.
I was successfully created cxf wsdl web-services in grails. Now i want configure cxf simple front end endpoint.
I was successfully configure cxf endpoint in resource.xml file in grails project.
Like..
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:simple="http://cxf.apache.org/simple"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd
http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!--create CXF service-->
<simple:server serviceClass="com.j2.signup.FaxSignupService" address="/FaxSignupService">
</simple:server>
</beans>
But i want same cxf endpoint configuration in resource.groovy DSL file instead of creating new resource.xml.
Anybody have idea about this?
You can use importBeans in place of the <import> elements
importBeans('classpath:META-INF/cxf/cxf.xml')
and for the <simple:server> you can duplicate this directly in the DSL (see "using Spring namespaces" at the end of this section of the user guide)
xmlns simple:'http://cxf.apache.org/simple'
simple.server(serviceClass:"com.j2.signup.FaxSignupService",
address:"/FaxSignupService")
If your FaxSignupService class itself needs dependencies injecting by Spring then you need to declare it as a top-level bean too
faxSignupService(com.j2.signup.FaxSignupService) { bean ->
bean.autowire = "byName"
}
xmlns simple:'http://cxf.apache.org/simple'
simple.server(serviceClass:"com.j2.signup.FaxSignupService",
serviceBean:"#faxSignupService",
address:"/FaxSignupService")
(NB if FaxSignupService is a genuine Grails service under grails-app/services then it is already registered as a bean by default and the extra bean definition is not required, just adding the serviceBean:'#faxSignupService' to the simple.server is enough.)
(First, I apologize, I can't get more than a single level of indention for my code)
I am attempting to write a unit test to test my service-layer methods. The interface for these service classes are annotated with #Preauthorize:
public interface LocationService {
void setLocationRepository(LocationRepository locationRepository);
/**
* Get all Location objects from the backend repository
* #return
*/
#PreAuthorize("has_role('ROLE_ADMIN')")
List<Location> getAll();
The unit test looks something like this:
#Before
public void setUp() {
admin = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin", "admin"));
user = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "user"));
// create Mock Repository
// set up the actual service WITH the repository
locationService = new LocationServiceImpl();
locationService.setLocationRepository(locationRepository);
}
#Test(expected = AccessDeniedException.class)
#SuppressWarnings("unused")
public void testGetAllAsUser() {
SecurityContextHolder.getContext().setAuthentication(user);
List<Location> resultList = locationService.getAll();
}
Finally, here is the security context from my applicationContext.xml:
<!-- Temporary security config. This will get moved to a separate context
file, but I need it for unit testing right now -->
<security:http use-expressions="true">
<security:form-login />
<security:session-management
invalid-session-url="/timeout.jsp">
<security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:password-encoder hash="plaintext" />
<security:user-service>
<security:user name="admin" password="admin"
authorities="ROLE_ADMIN" />
<security:user name="user" password="user"
authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:global-method-security
pre-post-annotations="enabled" proxy-target-class="true" />
Unfortunately, the #PreAuthorize tag is being ignored, allowing someone with ROLE_USER to run getAll().
Can anyone help?
Jason
Are you running the unit test with the spring junit runner?
Are you pointing to the correct spring configuration file for that unit test?
Have you configured load time weaving for the security aspects?
The line:
locationService = new LocationServiceImpl();
Creates a new location service, bypassing spring altogether. If you are using the spring junit runner then you should use #Resource to get the locationService injected so that you are using the spring bean and not just your pojo.