My first attempt at developing a simple authentication based REST services. I am trying to develop a RESTful web application using Jersey on Tomcat 8. I am using Apache Shiro for session management and authorization. Only HTTPS is supported.
All services require authentication, neither guest nor anonymous access is allowed. The request can be authenticated two ways.
If the user belongs to the list of users in web application, then the user logs in from a Web browser and Shiro simply validates if the current user is logged in and allows request to proceed. This is for the custom UI provided by the application itself.
If the request is from third party application, the username/password token are passed into the HTTP header authorization field for every service request. The users are managed by third party app and the app uses a common username/password for its users to access the web service. Such common users are prevented from logging in.
All service requests are filtered (web.xml):
<servlet>
<servlet-name>REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.unisys.cpf.ffm.filter.AuthenticationFilter</param-value>
</init-param>
</servlet>
<servlet-mapping>`enter code here`
<servlet-name>REST Service</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
The AuthenticationFilter class implements ContainerRequestFilter for authentication:
#Override
public ContainerRequest filter(ContainerRequest cr) {
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
//User is not logged in so get the authorization from header and authenticate
String auth = cr.getHeaderValue("authorization");
//Do Shiro authentication here.
}
return cr;
}
I have a web service which accepts form parameters and creates a resource. The Form parameters are dynamic based on what user selects. So I cannot use #FormParam to get all the parameters. Also there may be more contents to form as new features are added so I do not want to touch the Service again for each new/removed parameter.
I am using the Chrome Advanced REST Client plugin to simulate third party requests. Any browser is fine for the first scenario (logged in user).
Now I know just two ways of accessing the form parameters.
First method is to use MultivaluedMap.
#POST
#Path("/create")
public String createResource(MultivaluedMap<String, String> parameters) {
System.out.println("Name of the resource: " + parameters.getFirst("resourceName"));
}
But trying to get the parameters using MultivaluedMap works only when a logged in user submits the form. If I submit from REST Client plugin the same form values, then all parameters return null.
Second method is to use #Context HttpServletRequest
#POST
#Path("/create")
public String createResource(#Context HttpServletRequest request) {
System.out.println("Name of the resource: " + request.getParameter("resourceName"));
}
This works for REST Client but does not work if a logged in user submits form. All request.getParameter return null.
If anybody knows how to fix the problem or better way to do authentication, then please let me know.
Related
I have a Spring Boot web application that is run on a Tomcat application server and authenticates against a third party IdP.
We currently do role based authentication in a number of our apps using <security-role> and <security-constraint> in a web.xml, and it works properly.
Now, attempting to use Spring Security, I have added the following configuration class:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
String[] publicPaths = /*get public paths from properties*/
String[] authorizedPaths = /*get authorized paths from properties*/
String[] authorizedRoles = /*get authorized roles from properties*/
http.csrf().disable()
.jee()
.mappableAuthorities(authorizedRoles)
.and()
.authorizeRequests()
.antMatchers(publicPaths).permitAll()
.antMatchers(authorizedPaths).hasAnyRole(authorizedRoles)
.and()
.logout().disable()
;
}
}
The authorizedRoles in the config above are roles that are authorized to access this application. However, there are other manual checks in the app that just call HttpServletRequest.isUserInRole() to determine if a user has a certain role. Before using Spring Security, that call would return true if that user had that role in the original request. After adding Spring Boot, that call only returns true if the role is one of those passed to .mappableAuthorities() in the example above. The roles that are checked via HttpServletRequest.isUserInRole() are stored in a database and can be updated often, so passing them to .mappableAuthorities() when the application loads is not feasible.
So, to get to the point of my question, it seems like Spring Security is modifying the original HttpServletRequest and taking out any roles that are not contained in the authorizedRoles passed to .mappableAuthorities().
Is there a way to avoid this behavior, or possibly pass some kind of wildcard to .mappableAuthorities(), so that you don't have to know all roles on application startup for them to be accessible via a call to HttpServletRequest.isUserInRole()? I've been looking at Spring Security documentation for hours and haven't found anything.
You can see only mapped roles, because SecurityContextHolderAwareRequestFilter wraps the HttpServletRequest:
A Filter which populates the ServletRequest with a request wrapper which implements the servlet API security methods.
It uses SecurityContextHolderAwareRequestWrapper to implement the servlet API security methods:
A Spring Security-aware HttpServletRequestWrapper, which uses the SecurityContext-defined Authentication object to implement the servlet API security methods:
getUserPrincipal()
isUserInRole(String)
HttpServletRequestWrapper.getRemoteUser().
To customize the roles mapping see J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource:
Implementation of AuthenticationDetailsSource which converts the user's J2EE roles (as obtained by calling HttpServletRequest.isUserInRole(String)) into GrantedAuthoritys and stores these in the authentication details object.
It uses a MappableAttributesRetriever to get the mappable roles:
Interface to be implemented by classes that can retrieve a list of mappable security attribute strings (for example the list of all available J2EE roles in a web or EJB application).
You could write your own MappableAttributesRetriever which loads the mappable roles from your database.
Or you can use WebXmlMappableAttributesRetriever, which retrieves the roles from web.xml:
This MappableAttributesRetriever implementation reads the list of defined J2EE roles from a web.xml file and returns these from getMappableAttributes().
I am new to java programming in the web environment and am having trouble understanding the flow.
For an assignment coming up I need to build a web application accessible with an API via get/post requests. For the tutorials that I have followed here is the flow I understand.
User visits top domain->
Per configuration user is directed to a jsp page->
Jsp contains javascrip and html. To access server code (for database, computations and other processes) the jsp page can use RCP to make async requests to a java servlet->
Java servlet does server handling and returns response to jsp page
Is this the required flow or can a user directly acess a servlet, and can that servlet handle get/post, or do I have to handle at the jsp and foward to the servlet?
Servlets can be accessed directly. You just need to extend HttpServlet and implement doGet and/or doPost. For example:
public class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
Integer param = null;
try {
param = Integer.parseInt(req.getParameter("param"));
}
catch(NumberFormatException e) {
}
}
}
You also need to map your servlet to url in web.xml:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.adam.test.server.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/my_servlet</url-pattern>
</servlet-mapping>
Now you can access your servlet using url like this:
http://domain.com/my_servlet?param=123
I have set up an App Engine Restlet Project (v 2.2.2) which returns a html or json response (web or android client) and different data from a db for different users. I have implemented HTTP basic authentication. It all works quite well.
my basic setup atm (I have simplified it ofc):
MyApplication.java
public class MyApplication extends Application {
private ChallengeAuthenticator authenticatior;
private ChallengeAuthenticator createAuthenticator() {...}
public boolean authenticate(Request request, Response response) {...}
#Override
public Restlet createInboundRoot() {
this.authenticatior = createAuthenticator();
Router router = new Router(getContext());
router.attachDefault(MyRestlet.class);
authenticatior.setNext(router);
return authenticatior;
}
MyRestlet.java
public class MyRestlet extends ServerResource {
#Get("json")
public Representation getJSON() {
MyApplication app = (MyApplication) getApplication();
if (!app.authenticate(getRequest(), getResponse())) {
// Not authenticated
return null;
}
else {
return data;
}
#Get("html")
public String getHTML() {...}
}
web.xml
<?xml ...>
<display-name>MyName</display-name>
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>x.MyApplication</param-value>
</context-param>
<servlet>
<servlet-name>MyRestlet</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyRestlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Now I want to add encryption and created keys/certificates. My guide was this tutorial. I wanted to try to add a simple component first, stay with HTTP and change the port to 8183 as done in this tutorial. I have now played around quite a bit and cannot seem to get my component to work. So my question is: Where would I put this main-Method (the following code is taken from the tutorial)? Into which class should I insert it or should I create a seperate server-class and what exactly would the required changes to the web.xml look like (I did not find much concerning this and I suspect that this is the central problem)? Any help is appreciated!
public static void main(String[] args) throws Exception {
// Create a new Restlet component and add a HTTP server connector to it
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
// Then attach it to the local host
component.getDefaultHost().attach("/trace", Part05.class);
// Now, let's start the component!
// Note that the HTTP server connector is also automatically started.
component.start();
}
Your question is slightly confusing, probably because of the path you have taken.
Your original plan creates a RESTlet web application, complete with web.xml to run inside a container, such as GAE, Jetty or Tomcat.
What you're proposing creates a component and starts a stand alone server (it starts an internal instance of Jetty). This won't work on Google App Engine.
You should continue with the web.xml approach and configure GAE to serve over https. See https://cloud.google.com/appengine/kb/general#https and https://cloud.google.com/appengine/docs/java/config/webxml#Secure_URLs for configuration instructions.
Also, another tip: return 403 status when something attempts to access a resource without authorisation.
So I was trying to convert a JavaSE RESTLET app to a JavaEE app. What I understood from the "Restlet in Action" book, Pg 72, is that we dont need to attach a server to the component as Servlet engine handles the incoming HTTP and HTTPS requests.
The tutorial also points to the component file an an INIT-PARAM or param-name in your web.xml. However for me, none of above 2 changes are working.
If I point to the application class as an INIT-PARAM and not use a HTTP connector as suggested in the book, i am able to access the APIs but not able to make any calls from the client class as I get the below error -
WARNING: The protocol used by this request is not declared in the list of client connectors. (HTTP/1.1). In case you are using an instance of the Component class, check its "clients" property.
Not Found (404) - The server has not found anything matching the request URI
Hope these info help you in some way
EDIT
I found the solution to the above problem -
I had to add the below piece of code
<init-param>
<param-name>org.restlet.clients</param-name>
<param-value>HTTP HTTPS FILE</param-value>
</init-param>
Also for your problem, you need to configure the Component via an XML. Below URLs will give more info -
http://restlet.com/learn/javadocs/2.1/jee/ext/org/restlet/ext/servlet/ServerServlet.html
http://restlet.com/learn/javadocs/2.1/jee/api/org/restlet/Component.html?is-external=true
I am trying to create a RestEasy client for services host in JBPM server. The service url is always redirecting to a form based login screen which expects j_username and j_password.
I need to login to the service and also have to store the cookies to avoid authentication everytime. Please suggest the best implementation to achieve this.
Now all the service calls ends up in returning the login html page.
I tried some of the solutions posted here, but not works in my scenario.
RESTEasy client framework authentication credentials
RestEasy Client Authentication and HTTP Put with Marshalling
First, write an authetication servlet (where you can intercept the login credentials and store them to your cookie):
#WebServlet(urlPatterns = {"/security_check"})
public class AuthenticationServlet extends HttpServlet
{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException
{
request.login(userName, userPassword);
StoreInCookieMethod(request.getUserPrincipal().getName(), userPassword);
response.sendRedirect(request.getContextPath() + "/protectedResourceUrlPattern/");
}
}
in the login_form, map the action to the servlet URL
eg:
<form method="post" action="security_check">
for all other requests other than login, define a url pattern(eg protectedResourceUrlPattern) and autheticate using the credentials from cookie
I'm a Ruby on Rails developer programming a web application in Java. I am trying to achieve something similar to what is achieved in Rails. In Rails it is possible to call a link using localhost:8000\Users\1 when Users is a Model and 1 is the id of a specific user. I would like to get the same kind of thing in Java.
I am working in an MVC type design where my JSP pages are the view and my Servlets are the controllers. I created a servlet called Users which renders the users.jsp page now i can get to that page using the URL localhost:8000\projectName\Users, i would like to route localhost:8000\projectName\Users\1 to the page user.jsp while the appropriate Servlet will handle sending into the page the correct user (with id=1).
Any idea how I can achieve this?
I'm doing this in a University project and am not allowed to use any frameworks. I also would rather something i could code rather than install.
now i can get to that page using the URL localhost:8000\projectName\Users, i would like to route localhost:8000\projectName\Users\1 to the page user.jsp while the appropriate Servlet will handle sending into the page the correct user (with id=1).
Simple. Map the servlet on an URL pattern of /Users/* instead of /Users. You can then grab the path info (the part after /Users in the URL, which is thus /1 in your example) as follows:
String pathInfo = request.getPathInfo();
// ...
You can just forward to users.jsp the usual way.
Long id = Long.valueOf(pathInfo.substring(1));
User user = userService.find(id);
request.setAttribute("user", user);
request.getRequestDispatcher("/WEB-INF/users.jsp").forward(request, response);
I would try this via a servlet and servlet mappings like that in web.xml
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.example.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/Users</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/Users/*</url-pattern>
</servlet-mapping>
Than in your UserServlet try to get the full URL and parse it to your needs. Example:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String url = reg.getRequestURL();
//... get last part after slash and parse it to your id
}
See http://download.oracle.com/javaee/1.3/api/javax/servlet/http/HttpServletRequest.html for further documentation on the request and how its parameters can be retrieved
UrlRewriteFilter is like mod_rewrite but for Tomcat. You can use it to make your URLs SEO-friendly. You can also use Apache+mod_rewrite+Tomcat.