Restful Java - Grant access to resources - java

I developing a resful webservice that will have differentes resources (the application database stores urename and password).
On the other and I have a client that can access to those resources. To access to some of these resources the client must be registered (existing in the database). Im using GAE as application server and Jersey to create the Restful WS, so my question is what is the best way to access this resources?
I thought in sending the username and password in the WS request (as POST) and then check if the couple exists in the db and answering at the request.
Do you think this kind of authentication is secure (I dont think I can use https on GAE)?
Thanks in advance fo the responces
Danilo

You should be using OAuth 1.0 or 2.0

You might want to use some form of transport layer security such as SSL to secure your service.
Also, REST tries to make use of HTTP features, so you could put a Authorization header in the HTTP request.
Edit: a simple example
Transport Layer Security
Go to one of the many companies that sell SSL certificates, for example Verisign. Buy a certificate. Install it on your web server. You web server will have documentation on how to install it.
Using HTTP authorisation
Get the client of your web service to use BASIC authorization (they are passed in plaintext so you've got to be using SSL for this to be effective). This involves putting the BASE64 encoded username and password in the Authorisation header. Write a security Filter and configure your web app to pass all requests to your RESTful service through the filter. Your security filter should extract the username and password from the request Authorisation header and check them. If the credentials are invalid you reject the request with a 403 status code. If the credentials are OK, just propogate up the filter chain.
public MySecurityFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
//Get the Authorizatiuon header
String auth = ((HttpServletRequest)request).getHeader("Authorization");
//Extract the username and password
if (checkCredentialsOnMyDatabase(credentials[0], credentials[1])) {
chain.doFilter(request, response);
} else {
//Reject the request with status code 403
}
}
}
Also note that if you are using one of the popular frameworks like Jersey then it has a lot of security functions built in that may help you.

Related

Redirect way except Ajax/Javascript to send the authentication request to avoid CORS error

Issue description:
Assuming I have one web application(Java+Saml2.0) who has a Sign in button to call ADFS(an identity provider) to authenticate.
It's using Javascript(Ajax has same issue) to call one endpoint of ADFS 2016. Since the request if sending from Javascript/Ajax, the browser would throw CORS error. (The ADFS2016 server side doesn't support modifying CORS header/response/origins)
And I heard from someone that one way to avoid the CORS error is to use redirect instead of using Ajax/Javascript to directly call one URL/endpoint.
Can someone give some insights for this situation? How can I modify my code to do such redirect without causing CORS?
PS: I don't want to lower browser security level to bypass CORS and I also don't want to upgrade to ADFS2019 though it supports customizing CORS origins.
Im not sure if you are trying to achieve some special case by using javascript like this. But normally when authenticating a using using SAML you issue a HTTP redirect from the backend as a response to the user clicking the login button.
To understand it all it is important to first understand the SAML authentication flow as I go through in this post.
The user triggers authentication by navigating to a protected page or in this case clicking a button
The application, or Service Provider(SP) in SAML speak, builds a SAML authentication request and sends it to the IdP by adding it as a URL parameter and sending a backend HTTP Redirect to the user. The authentication request can also be sent using HTTP POST explained here
The IdP authenticates the user in the way it sees fit.
The IdP send the user back to the SP using HTTP POST together with a SAML Response and SAML Assertion. This contain the result of the authentication as well as any extra information about the user.
The SP, you application, interprets the SAML Response and lets the user through to the protected application.
This redirect contains a encoded SAML authentication request in the URL that is parsed by ADFS to understand where the authentication request is coming from and how authenticates the user.
There are several libraries and frameworks for managing SAML trafic including the sending the messages using redirect or other methods. If you are using Java, Spring has SAML management as a part of their security framework. Another library is the PAC4J which provides a SAML module
While both of these work well for the most general use case of building a SP to integrate with a existing IdP, if you need to do more custom cases or build a IdP on your own OpenSAML can be an alternative.
OpenSAML is a more low level library for handling SAML. In this write up on my blog I show how to build and send a SAML authentication request using redirect from OpenSAML.
Below is a simplifies example for using OpenSAML. For a full example see the sample code here and here
The authentication request is build using OpenSAML
AuthnRequest authnRequest = OpenSAMLUtils.buildSAMLObject(AuthnRequest.class);
authnRequest.setIssueInstant(Instant.now());
authnRequest.setDestination(IPD_SSO_DESTINATION);
authnRequest.setProtocolBinding(SAMLConstants.SAML2_ARTIFACT_BINDING_URI);
authnRequest.setAssertionConsumerServiceURL(SP_ASSERTION_CONSUMER_SERVICE_URL);
authnRequest.setID(RANDOM_ID);
authnRequest.setIssuer(ISSUER);
authnRequest.setNameIDPolicy(NAME_ID_POLICY);
Add the message to a message context and set set destination
MessageContext context = new MessageContext();
context.setMessage(authnRequest);
SAMLPeerEntityContext peerEntityContext = context.getSubcontext(SAMLPeerEntityContext.class, true);
SAMLEndpointContext endpointContext = peerEntityContext.getSubcontext(SAMLEndpointContext.class, true);
endpointContext.setEndpoint(MESSAGE_RECEIVER_ENDPOINT);
Send the message using HTTP Redirect
HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
encoder.setMessageContext(context);
encoder.setHttpServletResponse(httpServletResponse);
encoder.initialize();
encoder.encode();
For those who want to dig in deeper I have have written a book on working with OpenSAML, A Guide to OpenSAML, as well as book on SAML as a framework, SAML 2.0: Designing secure identity federation.
I also have a ton resources on my blog

Calling a rest webservice from html..Passing in credentials

When a html page makes a call to a rest webservice, how can the service credentials be sent in the request?
The username and pwd needed by the service can be sent in the request itself by using (usename:pwd#service.com) notation, but that would not be wise sending in the creds in the request itself.
Any other ways to solve this problem?
If it uses BASIC authentication, it is sent along the request as a header (in clear). Have a look at:
http://en.wikipedia.org/wiki/Basic_access_authentication
This can be hardened by using a secure protocol (https), with which you encode your request (basic authentication included).
http://en.wikipedia.org/wiki/HTTP_Secure
This requires additional configuration on the server-side

Sample about RESTful and Shiro Integration

I am developing a Java web application using RESTful as web service. And now I want to apply Apache Shiro to secure my application. The mechanism is: after user logged in successfully, a token (combined from username, password and logged time) will be returned to client. Then every single REST request will attach this token to authenticate at server (no need to authorize). But now I dont know how to configure to accept this.
And by the way, could you please give me any sample about Shiro & RESTful integration? Thank you
If the REST application and the Java web application are the same Webapp, then you only need to check subject.isAuthenticated(). Use a session cookie without the password or username (it isn't a good idea to be passing around the password as it could be stolen).
Most of this behavior comes by default if both parts are in the same Webapp.
In your REST method you'd have something like:
Subject subject = SecurityUtils.getSubject();
if(subject == null || !subject.isAuthenticated()) {
return 401; // Not Authorized
}
Hope that helps.
In addition to the above response, you can send back a token (session-id) from your REST Server, post successful login. Your iOS/Android application will then need to store this, and send this with every REST request it makes. Here is sample of what your post login REST response can be:
session-start-timestamp: 1394683755389,
session-timeout: 1800000,
session-id: "068C8E0E289788A7ABC5FE47B2CC0D28"
The session-id will be maintained by your REST Server, and its TTL will be reset every time a new request with this id comes in.
On browsers, this id gets sent automatically. For your case, you would want to send it explicitly with each HTTP request (which is what REST request is)
Hope this helps

Preprocessing a REST request for BASIC authentication on tomcat + JAX-RS

I'm developing a REST api and i want to use apply BASIC authentication on it.
What i want to do :
Intercept request for methods like GET, PUT, POST, DELETE.
Fetch username and password from authorization header.
Authenticate User by validating UserName + Password from database.
Accordingly allow or deny access to service.
I'm using Apache Tomcat 7, JAX-RS for this project.
So what is the best way to achieve this?
Write a ServletFilter to intercept all the incoming request to your REST web services. Depending on the authentication, doFilter the request to your REST webservice or deny with 401.

Disable redirect to last accessed resource on form login Glassfish

I'm going to rewrite my previous question.
Glassfish redirects after form login to the last accessed resource, how do I go about to turn this off?
Our problem is that we get 415 in FF and IE because if I have a JSESSION cookie Glassfish will redirect to the last resource I tried to access but does not switch content type from (x-form-urlencoded).
Pseudo example (requests are the browsers' XMLHttpRequest):
GET /secure/resouce1 (json) -> Response "you're not logged in."
GET /login.xhtml
POST /j_secure (x-form-urlencoded) -> New location /secure/resource1 (x-form-urlencoded)
GET /secure/resource1 (x-form-urlencoded) <- HTTP ERROR 415 content type not JSON.
You will probably need to write a Filter to check for and catch that case. I like this tutorial (hoping the translation to English is understandable).
In my opinion it is better to use Basic or Digest authentication over SSL for RESTful services. Other options are including the credentials as part of the payload or creating a dedicated login service, which accepts credentials and returns a token. There are various reasons why form based authentication is less suitable for RESTful service: it requires a session, it does not use the existing HTTP Authorization and more.
If you need to call your RESTful service using AJAX then using a cookie for authentication can be a valid solution. They should only affect if the user can make a call, but not how the server responds.
If you would like to keep using form based authentication for your application I would suggest adding an additional JAAS authentication provider which will handle the RESTful services authentication. You can read more about it here.
Another option, which should be easier than JAAS, would be using Spring Security or Apache Shiro instead of the container based authentication.
Here is an example of configuring form based authentication with Spring Security. This post shows an example of how to secure RESTful services using Spring Security.
in your login page
reset the JSESSIONID cookie to prevent redirect last page
// login_form.jsp
Cookie jsess = new Cookie("JSESSIONID", null);
jsess.setMaxAge(0);
jsess.setPath(pageContext.getServletContext().getContextPath());
response.addCookie(jsess);

Categories

Resources