I need to remember the original URL of the Http Request, then redirect this request to a web form for a user authentication. In case of a successful authentication, the user must be redirected to the original URL just remembered above.
I am using JBoss 7.1.1 Final, a standard web.xml, and the JBoss Login Module org.jboss.security.auth.spi.DatabaseServerLoginModule:
I had referred the following links which didn't answer my question completely:
Precedence of security-constraint over filters in
Servlets
Jaspic ServerAuthModule delegating to JAAS Krb5LoginModule
Implementing container authentication in Java EE with JASPIC
Oracle GlassFish Server 3.0.1 Application Development Guide
However, after impltementing my solution, my custom ServerAuthModule is not called at all. What is even worse, I did not get any HttpResponse from the server. Something got broken, please help!
My web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>All resources in /pages/*</web-resource-name>
<description>All resources in /pages/*</description>
<url-pattern>/pages/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>general</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<display-name>Restrict direct access to the /resources folder.</display-name>
<web-resource-collection>
<web-resource-name>The /resources folder.</web-resource-name>
<url-pattern>/resources/*</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsf</form-login-page>
<form-error-page>/loginFailed.jsf</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>general</role-name>
</security-role>
My jboss-web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>jBossJaasMysqlRealm</security-domain>
<valve>
<class-name>org.jboss.as.web.security.jaspi.WebJASPIAuthenticator</class-name>
</valve>
</jboss-web>
My standalone.xml:
<security-domain name="jBossJaasMysqlRealm" cache-type="default">
<authentication-jaspi>
<login-module-stack name="lm-stack">
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName" value="java:/MySqlDS_IamOK"/>
<module-option name="principalsQuery" value="select password from user where username=?"/>
<module-option name="rolesQuery" value="select role, 'Roles' from user_role where username=?"/>
</login-module>
</login-module-stack>
<auth-module code="at.alex.ok.web.utils.RequestMarkerServerAuthModule" login-module-stack-ref="lm-stack"/>
</authentication-jaspi>
</security-domain>
My custom WebServerAuthModule:
import org.jboss.as.web.security.jaspi.modules.WebServerAuthModule;
public class RequestMarkerServerAuthModule extends WebServerAuthModule {
public static final String ORIGINAL_URL = "originalURL";
protected static final Class[] supportedMessageTypes = new Class[] {
HttpServletRequest.class, HttpServletResponse.class };
public void initialize(MessagePolicy reqPolicy, MessagePolicy resPolicy,
CallbackHandler cBH, Map opts) throws AuthException {
System.out.println( this.getClass().getName() + ".initialize() called");
}
public Class[] getSupportedMessageTypes() {
return supportedMessageTypes;
}
public AuthStatus validateRequest(MessageInfo msgInfo, Subject client,
Subject server) throws AuthException {
try {
System.out.println( this.getClass().getName() + ".validateRequest() called");
processAuthorizationToken(msgInfo, client);
return AuthStatus.SUCCESS;
} catch (Exception e) {
AuthException ae = new AuthException();
ae.initCause(e);
throw ae;
}
}
private void processAuthorizationToken(MessageInfo msgInfo, Subject s)
throws AuthException {
HttpServletRequest request = (HttpServletRequest) msgInfo
.getRequestMessage();
String originalURL = request.getRequestURL().toString();
request.getSession().setAttribute(ORIGINAL_URL, originalURL);
}
public AuthStatus secureResponse(MessageInfo msgInfo, Subject service)
throws AuthException {
System.out.println( this.getClass().getName() + ".secureResponse() called");
return AuthStatus.SEND_SUCCESS;
}
public void cleanSubject(MessageInfo msgInfo, Subject subject)
throws AuthException {
System.out.println( this.getClass().getName() + ".cleanSubject() called");
}
}
This question is put incorectly, because:
For a redirect to the originally requested URL after a successfull login, there is no need to implement a custom ServerAuthModule for JBoss.
The interface javax.servlet.RequestDispatcher has the constant FORWARD_REQUEST_URI, which denotes the name of the Http-Request attribute under which the original request URI is made available to the processor of the forwarded request.
Using JSF 2.2 and a View-Scoped backing bean LoginBean, my solution is simply to obtain the originally requested URL in a #PostConstruct method of the backing bean, and store it in a session attribute, as follows:
#ManagedBean(name="loginBean")
#ViewScoped
public class LoginBean {
private String originalURL;
#PostConstruct
private void init() {
ExternalContext extCtx = FacesContext.getCurrentInstance().getExternalContext();
String origURL = (String) extCtx.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
HttpServletRequest request = (HttpServletRequest) extCtx.getRequest();
HttpSession session = (HttpSession)extCtx.getSession(false);
if (session == null){
session = (HttpSession)extCtx.getSession(true);
}
if (origURL!=null && session.getAttribute(ORIGINAL_URL) == null){
String applicationName = request.getContextPath();
origURL = origURL.substring(applicationName.length(), origURL.length());
session.setAttribute(ORIGINAL_URL, origURL);
}
}
Then, in the login() method of the same backing bean, redirect the user to the originally requested URL in case of a successfull log-in like this:
public String login() {
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
try {
request.login(this.getLogin(), this.getPassword());
} catch (ServletException e) {
// handle bad username / password here
}
return this.originalURL + "?faces-redirect=true";
}
Related
Hey there im currently working on a application in tomcat and im trying to access a DataSource thats defined in the tomcat's server.xml. However im unable to access the resource and it will always return an empty DataSource. The servlet is able to access resources defined on the local level. My question is why is my application unable to access global resources?
The exception im getting when trying to access the database is: java.sql.SQLException: Cannot create JDBC driver of class '' for connect URL 'null'
server.xml
<GlobalNamingResources>
<Resource name="jdbc/AuthenticationDatabase" auth="Container" type="javax.sql.DataSource" username="tomcat" password="tomcat" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/tomcat" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" />
</GlobalNamingResources>
AdminPanel.java
#WebServlet(name = "adminpanel", value = "/restricted/user-management")
public class AdminPanel extends HttpServlet {
private List<User> users;
private final String PreparedUsersSelectQuery = "SELECT active, user_name FROM users";
private final String PreparedRoleSelectQuery = "SELECT role_name FROM user_roles WHERE user_name = ?";
Context initCtx = new InitialContext();
Context EnvCtz = (Context) initCtx.lookup("java:comp/env");
DataSource userDB = (DataSource) EnvCtz.lookup("jdbc/AuthenticationDatabase");
public AdminPanel() throws NamingException {
}
protected void ProcessRequest(HttpServletRequest request, HttpServletResponse response) {
users = new ArrayList<>();
try {
Connection conn = userDB.getConnection();
PreparedStatement stmt = conn.prepareStatement(PreparedUsersSelectQuery);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
User user = new User(rs.getString("user_name"), rs.getBoolean("active"));
PreparedStatement roleStmt = conn.prepareStatement(PreparedRoleSelectQuery);
roleStmt.setString(1, user.username);
ResultSet roleResults = roleStmt.executeQuery();
while (roleResults.next()) {
user.roles.add(roleResults.getString("role_name"));
}
users.add(user);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
request.setAttribute("data", users);
RequestDispatcher dispatcher = request.getRequestDispatcher("ListUsers.jsp");
try {
dispatcher.forward(request, response);
} catch (ServletException | IOException e) {
throw new RuntimeException(e);
}
}
public void init() {
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
ProcessRequest(request, response);
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ProcessRequest(req, resp);
}
public void destroy() {
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<resource-ref>
<description>Access to the userdatabase for the purpose of modifying the user data</description>
<res-ref-name>jdbc/AuthenticationDatabase</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin Panel</web-resource-name>
<url-pattern>/restricted/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin-user</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>admin-user</role-name>
</security-role>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>User Management</realm-name>
</login-config>
</web-app>
Thanks for any and all assistance in this matter.
I have a servlet deployed
Myservlet.java
#Configurable
public class MyServlet extends HttpServlet {
#Autowired
MyService service;
#Override
public void init(ServletConfig config) throws javax.servlet.ServletException{
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) {
//Do something here
}
Now the security for this is enabled in web.xml as :
<security-constraint>
<web-resource-collection>
<web-resource-name>myServlet</web-resource-name>
<url-pattern>/myUrl/*</url-pattern>
<http-method>HEAD</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>user</role-name>
</security-role>
But where this spring application deployed already has a spring security enabled via #EnableWebSecurity
The controllers deployed in the spring application are all correctly getting authenticated as expected. But the servlet is not authenticating with spring security. I believe what's mentioned in the is stopping it from authenticating.
How do i make the servlet work with Spring security ?
Edit 1:
Spring security configuration: (Note that this is not syntactically correct) but user/role and datasource are all correct in my code. It's working fine for other REST apis deployed in spring application
#Configuration
#EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
String user_query = "select user from userTable where id=9999";
String role_query = "select role from roleTable where id=6666";
logger.info("Using the following query for role : " + role_query);
auth.
jdbcAuthentication()
.dataSource(dataSource) //Datasource is injected to this class
.usersByUsernameQuery(user_query)
.passwordEncoder(passwordEncoder())
.authoritiesByUsernameQuery(role_query);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().hasRole("myrole")
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(runAsAuthenticationProvider());
}
#Autowired
protected RunAsManager runAsManager() {
RunAsManagerImpl runAsManager = new RunAsManagerImpl();
runAsManager.setKey("MyRunAsKey");
return runAsManager;
}
A Java servlet application has been changed so that it no longer requires certificate authentication.
That part works correctly. However, the application no longer connects to the database and throws the following exception:
> REMOTE USER IS null MY URL is 0:0:0:0:0:0:0:1 NULL GENERICPRINCIPAL
> Apr 01, 2021 12:43:11 PM org.apache.catalina.core.StandardWrapperValve
> invoke SEVERE: Servlet.service() for servlet
> [com.harris.cpd.resource.ApplicationConfig] in context with path
> [/cpd] threw exception [java.lang.NullPointerException] with root
> cause java.lang.NullPointerException at
> com.harris.cpd.resource.CPDResource.getTomcatUserRole(CPDResource.java:116)
The following is web.xml with changes shown in comments.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>cpd</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>chemicals.html</welcome-file>
</welcome-file-list>
<!-- THIS IS NEW CODE -->
<filter>
<filter-name>CPDAuthenticationFilter</filter-name>
<filter-class>com.harris.cpd.filter.CPDAuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CPDAuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- THIS SECTION IS NEW CODE -->
<servlet>
<servlet-name>cpd</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>cpd</servlet-name>
<url-pattern>/cpd/*</url-pattern>
</servlet-mapping>
<!-- THIS SECTION IS NOW COMMENTED OUT
<security-constraint>
<web-resource-collection>
<web-resource-name>BasicSecurity</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
<http-method>PUT</http-method>
</web-resource-collection>
<auth-constraint>
<description>Authorized role is librarian</description>
<role-name>DOMAIN_LIBRARIAN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>BasicSecurity</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>PUT</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<description>Authorized role is guest and librarian</description>
<role-name>DOMAIN_LIBRARIAN</role-name>
<role-name>DOMAIN_GUEST</role-name>
</auth-constraint>
</security-constraint> -->
<!-- THIS IS NEW CODE AND PROVIDES THE BASIC LOGIN -->
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Login</realm-name>
</login-config>
<!-- THIS CODE IS NOW COMMENTED OUT
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>IAASecurityRealm</realm-name>
</login-config> -->
<security-role>
<description>A Guest User in the system</description>
<role-name>DOMAIN_GUEST</role-name>
</security-role>
<security-role>
<description>A Guest User in the system</description>
<role-name>DOMAIN_LIBRARIAN</role-name>
</security-role>
<!--
<security-role>
<description>A Guest User in the system</description>
<role-name>GUEST</role-name>
</security-role>
<security-role>
<description>A Guest User in the system</description>
<role-name>LIBRARIAN</role-name>
</security-role>
-->
</web-app>
And here is CPDAuthenticationFilter.java which is the filter code.
One line was deleted below:
UserRole role = auth.authenticate(authCredentials);
The following line replaced it, hard-coding "role":
UserRole role = UserRole.DOMAIN_LIBRARIAN;
package com.harris.cpd.filter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.harris.cpd.authentication.AuthenticationService;
import com.harris.cpd.authentication.UserRole;
//#WebFilter(filterName="authentication", urlPatterns="/resources/*")
public class CPDAuthenticationFilter implements Filter {
private final static Logger logger = Logger.getLogger(CPDAuthenticationFilter.class.getPackage().getName());
public static final String AUTHENTICATION_ATTR = "cpd.authenticate";
public static final String USER_ROLE_ATTR = "cpd.user.role";
/* (non-Javadoc)
* #see javax.servlet.Filter#destroy()
*/
#Override
public void destroy() {
}
/* (non-Javadoc)
* #see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filter)
throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if (httpServletRequest.isUserInRole(UserRole.DOMAIN_GUEST.toString())) {
logger.log(Level.INFO, "found a guest user");
}
else if (httpServletRequest.isUserInRole(UserRole.DOMAIN_LIBRARIAN.toString())) {
logger.log(Level.INFO, "found a domain_librarian user");
}
else {
logger.log(Level.INFO, "found invalid user: "+httpServletRequest.getRemoteUser());
}
String authCredentials = httpServletRequest.getHeader(AUTHENTICATION_ATTR);
AuthenticationService auth = new AuthenticationService();
// CRM : TEST access 8080 without login:
//UserRole role = auth.authenticate(authCredentials);
UserRole role = UserRole.DOMAIN_LIBRARIAN; //CGN 3-25 TURNING OFF WHAT CHRIS HAD
logger.log(Level.INFO, "user role: " + role);
if (role.equals(UserRole.DOMAIN_GUEST) || role.equals(UserRole.DOMAIN_LIBRARIAN)) {
request.setAttribute(USER_ROLE_ATTR, role);
filter.doFilter(request, response);
} else {
if (response instanceof HttpServletResponse) {
logger.log(Level.INFO, "failed BASIC authentication");
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
}
/* (non-Javadoc)
* #see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
#Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("init the authentication filter (RestAuthenticationFilter)");
}
}
The errors that shows up on the Chrome debug tools for the client side:
-- LOADING APP (index.html) --
:8080/cpd/resources/categories:1 Failed to load resource: the server responded with a status of 500 ()
angular.js:14516 -- db: getProcessCategories url:http://localhost:8080/cpd/resources/categories procCats 500 failed --
So the problem presents itself as servlet error, and the database is not connecting, returning anything, with just the changes I have shown above.
I don't think this exception was related to database connection.
according to the exception which you have faced.
getTomcatUserRole(CPDResource.java:116)
I think there is another class like CPDResource.java that has been affected by this change
<!--
<security-role>
<description>A Guest User in the system</description>
<role-name>GUEST</role-name>
</security-role>
<security-role>
<description>A Guest User in the system</description>
<role-name>LIBRARIAN</role-name>
</security-role>
-->
and you should set it as a hardcode instead of getting from roles as before.
I have secured my a Spring application with KeyCloak using Spring Security Adapter, this works fine on my local machine, but when i deployed the WAR on tomcat and try to call the API, i get the following internal server error :
o.s.b.w.servlet.support.ErrorPageFilter : Forwarding to error page from request [/api/statutOperations]
due to exception [null]
java.lang.NullPointerException: null
at org.keycloak.adapters.KeycloakDeploymentBuilder.internalBuild(KeycloakDeploymentBuilder.java:57) ~[keycloak-adapter-core-10.0.2.jar:10.0.2]
at org.keycloak.adapters.KeycloakDeploymentBuilder.build(KeycloakDeploymentBuilder.java:202) ~[keycloak-adapter-core-10.0.2.jar:10.0.2]
at org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver.resolve(KeycloakSpringBootConfigResolver.java:39) ~[keycloak-spr
Did i miss something, or is my configuration wrong, below is the necessary config :
Keycloak Config :
#Configuration
public class KeycloakConfig {
#Bean
KeycloakSpringBootConfigResolver configResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
KeycloakRestTemplate keycloakRestTemplate(KeycloakClientRequestFactory keycloakClientRequestFactory) {
return new KeycloakRestTemplate(keycloakClientRequestFactory);
}
}
#KeycloakConfiguration
public class KeycloakSpringSecuriteConfig extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http); http.authorizeRequests().antMatchers("/api/**").authenticated().anyRequest().permitAll();
}
}
application.properties :
keycloak.realm=cirta
keycloak.auth-server-url=http://localhost:8085/auth
keycloak.resource=cirta-api
keycloak.public-client=true
keycloak.cors=true
keycloak.ssl-required=external
I also added the following context.xml keycloak.json and web.xml in META-INF and WEB-INF directories :
context.xml
<Context path="/cirtaapi">
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
</Context>
keycloak.json
{
"realm" : "cirta",
"resource" : "cirta-api",
"auth-server-url" : "https://localhost:8085/auth",
"ssl-required" : "external",
"enable-cors" : true
}
web.xml
<module-name>cirtaapi</module-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>Operations</web-resource-name>
<url-pattern>/api/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>app-manager</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>KEYCLOAK</auth-method>
<realm-name>cirta</realm-name>
</login-config>
<security-role>
<role-name>app-manager</role-name>
</security-role>
This has been fixed in keycloak 11.0.0. Similar question is out there to describe this: NPE when loading custom SecurityConfig for Keycloak in WebMvcTest and provide a workaround for version 9.0.1 to 10.
See also: https://github.com/gtiwari333/spring-boot-web-application-seed/blob/master/main-app/src/main/java/gt/app/config/security/SecurityConfig.java
In order to use the security annotations of JSR-250 (RolesAllowed, PermitAll, DenyAll):
In Jersey, you would register the RolesAllowedDynamicFeature class.
In RESTeasy, you would use the web.xml config:
<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>
Both of these rely on the implementation of SecurityContext.isUserInRole(), but it seems that WebSphere Liberty Profile does not.
How do we get this to work in WebSphere Liberty Profile (WLP)?
I used a minimal example:
Create a resource class/method with #RolesAllowed:
#Path("/rest")
public class HelloWorld {
#GET
#RolesAllowed("ANYTHING")
public Response hello() {
return Response.ok("Hello World").build();
}
}
Set your SecurityContextImpl in a filter, overriding isUserInRole() to always returns true;
Enable "role-based security" for the JAX-RS implementation. (Jersey or RESTeasy, etc as above. For WLP, I had to add the appSecurity-2.0 feature)
And you should have a working example.
However, it appears that WebSphere Liberty Profile returns 403 Forbidden even though isUserInRole returns true.
Does anyone know how to properly use the #RolesAllowed annotation in Liberty and what I might be missing?
Code
#ApplicationPath("/")
public class MyApplication extends Application {
public MyApplication() {}
}
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext ctx) throws IOException {
System.out.println("Setting SecurityContext..");
ctx.setSecurityContext(new MySecurityContext("someuser", "anyrole"));
}
}
public class MySecurityContext implements SecurityContext {
private String user;
private String role;
public static class MyPrincipal implements Principal {
private String name;
public MyPrincipal(String name) { this.name = name; }
#Override public String getName() { return name; }
}
public MySecurityContext(String user, String role) {
this.user = user;
this.role = role;
}
#Override public String getAuthenticationScheme() { return "BASIC"; }
#Override public Principal getUserPrincipal() { return new MyPrincipal(user); }
#Override public boolean isSecure() { return true; }
#Override
public boolean isUserInRole(String role) {
return true;
}
}
#Path("/test")
public class HelloWorld {
#GET
#RolesAllowed("doesntmatter")
public Response hello() {
return Response.ok("Hello World").build();
}
}
pom.xml (dependencies only)
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
server.xml
Code works with the appSecurity feature disabled. Does not work with it enabled.
<server description="test">
<featureManager>
<feature>jaxrs-2.0</feature>
<feature>localConnector-1.0</feature>
<!-- <feature>appSecurity-2.0</feature> -->
</featureManager>
<webApplication id="RoleTest" location="RoleTest.war" name="RoleTest"/>
<httpEndpoint httpPort="9081" httpsPort="9444" id="defaultHttpEndpoint"/>
<!-- below lines are required when appSecurity feature is loaded -->
<!--
<keyStore id="defaultKeyStore" password="{xor}Lz4sLCgwLTtu"/>
<basicRegistry id="basic" realm="BasicRegistry">
<user name="username" password="password" />
</basicRegistry>
-->
</server>
May be you can try this:
1 server.xml
<server description="test">
<featureManager>
<feature>jaxrs-2.0</feature>
<feature>appSecurity-2.0</feature>
</featureManager>
<webApplication id="RoleTest" location="RoleTest.war" name="RoleTest">
<application-bnd>
<security-role name="ANYTHING">
<user name="username" />
</security-role>
<security-role name="AuthenticationRole">
<user name="username" />
</security-role>
<security-role name="AllAuthenticated">
<special-subject type="ALL_AUTHENTICATED_USERS" />
</security-role>
</application-bnd>
</webApplication>
<httpEndpoint httpPort="9081" httpsPort="9444" id="defaultHttpEndpoint" />
<basicRegistry id="basic" realm="BasicRegistry">
<user name="username" password="password" />
</basicRegistry>
</server>
2 Java Code
Create a MyApplication class and a resource class/method with #RolesAllowed:
#ApplicationPath("/")
public class MyApplication extends Application {
public MyApplication() {}
public Set<Class<?>> getClasses(){
Set<Class<?>> classes = new HashSet();
classes.add(HelloWorld.class);
return classes;
}
}
#Path("/rest")
public class HelloWorld {
#GET
#RolesAllowed("ANYTHING")
public Response hello() {
return Response.ok("Hello World").build();
}
}
3 web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee web-app_3_0.xsd"
version="3.0">
<display-name>Test Application</display-name>
<description>blablabla</description>
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>requestProcessorAttribute</param-name>
<param-value>requestProcessorAttribute_webcontainer</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>com.xxx.MyApplication</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SecurityContextApp</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>com.xxx.MyApplication</servlet-name>
<url-pattern>/xxx/*</url-pattern>
</servlet-mapping>
<security-constraint id="SecurityConstraint_2">
<web-resource-collection id="WebResourceCollection_2">
<web-resource-name>com.xxx.MyApplication
</web-resource-name>
<description>Protection area for Rest Servlet</description>
<url-pattern>/xxx/rest</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint id="UserDataConstraint_2">
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
<auth-constraint id="AuthConstraint_2">
<role-name>AuthenticationRole</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>test</realm-name>
</login-config>
<security-role id="SecurityRole_1">
<description>blabla</description>
<role-name>ANYTHING</role-name>
</security-role>
<security-role id="SecurityRole_2">
<role-name>AuthenticationRole</role-name>
</security-role>
</web-app>
Any other issues, leave me a message.