Should links contains the authentication token in HateOAS? - java

I'm using Spring MVC and Spring HateOAS to make a restful and stateless JSON API.
Everything works fine. But i have a "conception" question. My API use an authentication token in every request. For example, you use the login API to get your authentication token, and when you call my API you must use it like this :
http://some_host/api/foo/bar?token=abcd
The API always respond a JSON and links are generated via Spring HateOAS. For exemple :
{
"label" : "foo",
"links" : [
"rel" : "self",
"href" : "http://some_host/api/foo/bar/1234656"
]
}
The question is : Should i add the authentication token in the generated URL ? (so it will be http://some_host/api/foo/bar/1234656?token=abcd)
I can't find any advice or convention for that.

Usually, authentication tokens are communicated via standard HTTP headers (such as the Authorization header in the case of HTTP Basic or Digest). The other common one is via a cookie. In Servlet environments, this is usually the JSESSIONID cookie.
Generally speaking, you shouldn't see authentication tokens passed as part of the request URL.

This is an old question, but the answer is definitely no.
http://some_host/api/foo/bar/1234656 is supposed to be the uniform identifier (URI) and location (URL) for that resource. It's the one URL you can rely on. You can always get the resource using that URL but you'll never get the resource with http://some_host/api/foo/bar?token=abcd again, because the token will expire.
Calling the URL with the token appended is one thing, but it should never appear in the link, because it has nothing to do with the resource. It's the client's responsibility to send the token, not the server's one.

Related

Persisting the refresh token of the Spring OAuth2RestTemplate

I have a mobile application that uses my Spring Boot backend for things like authentication and accessing data. A part of the Spring Boot application accesses data from a resource server using OAuth2. I stumbled across an oauth2 client library for Spring that does its magic and everything just works out of the box.
As I'm trying to figure out how this library does its work, I can't seem to find an answer to the way it handles refresh tokens. I'm aware that the oauth2client is bound to a session for each user but what happens when the session ends? Wouldn't the access and refresh tokens get lost?
I was looking for ways to persist the refresh token for each user in my database but I didn't find any support for that in the library. This leaves me wondering if I have to implement this myself or if there's even a need to do so.
Any advice is appreciated!
Basically OAuth2 architecture is used for 3rd-party authentication and authorization. In this mechanism the credentials remains secured and aren't passed on while everything works upon tokens! But you can use it to work implicitly for your own authentication too.
In your case first when you hit "/oauth/token"(default endpoint) along with the client-secret and client-Id and rest of the user credentials the algo checks for the user details in the DB and matches the secret and Id present in the header of the request. If everything goes fine it'll generate a bearer type - access and refresh token and will store these tokens in different collections in the database.This particular user is mapped to these tokens and can access /api's using them only.No user creds are required. You can use MongoTokenStore if you're using MongoDb for storing and accessing stored tokens.
Next you have to configure WebSecurity/AuthorizationServer/ResourceServer for checking endpoints and header tokens tokens, authentication and authorizaton of users and providing valid tokens access to the resource respectively.
Lastly when you have a valid access token and hit an api with a correct header request the server grants you permission to access the resource!
This is the basic functionality of the OAuth2.0.
Normally Access Tokens have a shorter lifetime while refresh tokens have comparitively larger lifetime. Once Access Token gets expired a new Access Token can be generated using the Refresh Tokens. If the Refresh Tokens gets expired then you have to hit the "/oauth/token" api again,complete the flow cycle and generate tokens again.After expiry when you hit an api with existing access token they are removed from the collection. This is the default architecture of this mechanism, rest you can make custom classes and modify its functionality according to your needs! This architecture is quite secure and is a good practise.
Screenshot Flow Diagram
Check this post from digitalocean.
Edits ----
Personally I used MongoDB where I made two collections -
AuthAccessTokens and AuthRefreshTokens namely where these two were
stored. Access Token object has an Id of associated RefreshToken
which helps to map these two together. Rest custom additional Info.
can also be added using TokenEnhancer. Therefore tokens will always
be present in the DB unless expired. And in layman's terms if you
are just focussing on Backend stuff you can always check for your
access tokens by hitting "/oauth/token" with correct user creds and
it will return the assigned token by fetching it from the DB, else
if you're developing full stack after generating the tokens on first
step just store them on client end either in browser's local storage
or app. And if you want to deliberately end the session like for
example in Logout just remove these tokens from their respective
collections.

Is exposing client secret a threat for implicit grant type in oauth 2?

I have an application which needs to implement oauth 2 for securing rest API. The simple flow will be when a user logs in they should have access to some protected resources ( as per their role).
I will be using angular 7 as front end.
as per this diagram I need to use implicit grant for Single Page Applications.
now i went on to search and found https://www.devglan.com/spring-security/spring-boot-oauth2-angular
API Name - Login
Method - POST
URL - oauth/login
Header - 'Authorization': 'Basic ' + btoa('devglan-client:devglan-secret')
Body - {'username' :'admin ',
'password' :'admin',
'grant_type': 'password' }
Content-type: application/x-www-form-urlencoded
Now my only concern in this approach is.
i. why this client id and client secret are revealed in angular code ? is client secret not supposed to be kept secret ?
We don't need any secret key to implement the implicit grant flow in the js applications.
You can see the following http url sample which needs few things such as client_id, redirect_uri etc.
We will get the access token in the url fragment of the redirect_uri, and this token authenticates you to access protected resources. However, scope parameter also plays an important to determine resources and its entitlements.
Http Request URI
https://YOUR_AUTH0_DOMAIN/authorize?
audience=YOUR_API_AUDIENCE&
scope=YOUR_SCOPE&
response_type=YOUR_RESPONSE_TYPE&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://YOUR_APP/callback&
nonce=YOUR_CRYPTOGRAPHIC_NONCE&
state=YOUR_OPAQUE_VALUE
I will highly suggest to go with Authorization Code Grant with PKCE even for the js applications because the access token is vulnerable to various security risks. With PKCE, the attacker needs to solve the puzzle (code challenge) in order to get the access token.

"Parameter client_assertion_type is missing" in keycloak

I am trying out get the access token from the super user so that I can the same to create new users in key cloak, I have deployed keycloak in wildfly and when I try to do the get call, I am getting Invalid user credentials as response,
How to know the actual credentials?
And when I try to update the password from the console, I getting the error message like below.
Since I am new to this and din't find enough information from internet also, any kind of help will be appreciated .
Updated:
Now i am getting new error description as Parameter client_assertion_type is missing like below. What should be client_assertion_type here ?
This keycloak help page describes the most likely reason for the second error:
Q: When logging in, I get an error: *Parameter client_assertion_type is missing [invalid_client].
A: This error means your client is configured with Signed JWT token credentials, which means you have to use the --keystore parameter when logging in.
Alternatively you can disable using JWT tokens for the client in Keycloak.
For your information, the client_assertion_type would probably be urn:ietf:params:oauth:client-assertion-type:jwt-bearer. But then you'd get another error because the client_assertion is missing.
If ccp-portal is a confidential client using client authentication with signed JWT then the Keycloak doc states that
During authentication, the client generates a JWT token and signs it
with its private key and sends it to Keycloak in the particular
backchannel request (for example, code-to-token request) in the
client_assertion parameter.
I guess it's not possible to generate a JWT with PostMan.
This is meant for backchannel client-keycloak communication, not for
user authentication.
Solutions
You can use the admin-cli as client_id instead of your ccp-portal client. The admin-cli should be in the list of clients configured for your ccp realm. You can see that from the Keycloak interface.
Another option is allow direct access grants in ccp-portal client config.
Finally you could use ccp-portal client in your application configured with one of the Keycloak client adapters, instead of POSTMan.
As subrob sugrobych mentionned, parameters should be passed as form-data.
first of all, when you are posting data to keycloak over a rest client, you need to input parameters as form paramaters, and not as query parameters. This is why you are getting this strange error of not providing parameter grant_type, when you obviously are providing it. Same is valid for accessing keycloak api via code.
Next thing you need to think about are roles for your superuser. You can assign realm roles and client roles. There is a client named 'realm-management' which contains roles which would normally count as "system roles". You will need to use them. When you are getting HTTP code 403, it means, that probably your user is missing a role from this client.

Implementing a token style security when doing GET requests

I'm implementing a temporary and very simple token-style authentication mechanism for an application.
The idea is very simple. Whenever a user logs in to the application, a token is returned to the client, which stores it in the sessionStorage data structure of the browser.
Now, whenever I do a request through AJAX I can send the token with the request and the server can verify if this token is associated with an authentication or username. If it is, it parses the request normally, if not, a error page or the initial page is returned or displayed.
I'm not sure if this is the way that token-style authentication and authorization is implemented in real or serious applications, but I've now no idea how to send the token when doing GET requests by just clicking on the link of a view.
My only idea would be to intercept the get requests so that I can fill them with the token, but this all seems to be quite odd, and I've already a lot of links and views.
Search for Json Web Tokens and for implementations on java. This is exactly what you need.
If you want to send to the user some sensitive data inside the jwt, use Json Web Encryption.
You can send that token on each request header or as a request parameter
You can set a cookie, ensure to set it httponly (ans secure if you are on an https site) and read the cookie on every request that reach the server.
You can use JWT token (see https://jwt.io/introduction/). JWT is basically a JSON data structure. Usually, the token is passed along in the authorization http header.

How to pass session id as part of Soap request?

I invoke an authentication request in order receive a session id :
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<loginResponse xmlns="urn:company" xmlns:ns2="urn:company">
<result>
<sessionId>2342422342.dc8bizxsfapi03</sessionId>
<msUntilPwdExpiration>2342342342342353452323</msUntilPwdExpiration>
</result>
</loginResponse>
</S:Body>
</S:Envelope>
In the docs for the Soap API that I'm using it states :
A successful login will return a
session ID as an HTTP Cookie. This cookie must be passed back to all subsequent HTTP
Requests that invoke API operations in order to authenticate.
How is the session id passed to the next http reqeust as this is not described ?
I'm assuming I need to embed the session ID within an XML tag as part of the subsequesnt request but this should be detailed in the API or is there a standard mechanism I can use ?
The API documentation you reference states that the service will set a cookie on the response that needs to be set on any subsequent request. Cookies are sent via HTTP headers, not the body of of the request/response, and are commonly used to establish and maintain sessions. The underlying HTTP client library the web service framework uses is well equipped to handle this for you, but because SOAP web services are designed to be stateless, you usually have to ask the framework if you want it to maintain sessions. When you enable this functionality, it simply means the framework will send any cookies back to the server that the server sends to it, which is precisely what your SOAP API documentation is asking that you do.
To enable this functionality in jax-ws, you set BindingProvider.SESSION_MAINTAIN_PROPERTY to true on the RequestContext. This article gives an example and more details.
Yes, that is a popular mechanism.
As the API states the session key was returned in the Cookie (it is a HTTP header). What is in a response body is only a repetition of the session key (I hope so). You need to extract the cookie from HTTP headers. If you are using the JAX-WS you may enable the session awareness using BindingProvider.SESSION_MAINTAIN_PROPERTY:
Hello proxy = new HelloService().getHelloPort();
((BindingProvider)proxy).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY,true);
String result = proxy.getMessage();
System.out.println(result);
If not, then try to find how to get and set the HTTP headers using your web services framework.
There are multiple ways you can extract the session id.
From the xml you have provided it seems the session id is in the xml response. If this is the case the you can use the method suggested by olyv and extract the session id from the xml response.
As lakshman suggest you could use groovy to parse the session id
from the xml response.
The below code may be of help.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder("Properties#response")
log.info holder.getNodeValue("//sessionId")
log.info holder['//sessionId']
This code and its explanation is available at Are you a hot cup? blog.
Another option using groovy is to extract the cookie from the header and store it in a property. The value of this property will be set in each request by creating a header property called cookie and assigning the session id to it. You'll have to verify the property name and value format by looking at the raw response/request.
try this code for example
//in script assertion
String message_size = messageExchange.responseHeaders["session-id"] /or whatever if the cookie name
or
def state = context.getProperty( com.eviware.soapui.model.testsuite.TestRunContext.HTTP_STATE_PROPERTY )
assert state != null : "Missing HttpState.. Try to set 'Maintain HTTP session' in test case options"
def cookies = state.cookies
Above code sample is from http://forum.soapui.org/viewtopic.php?t=3066#p10957
Lastly, there is a test case level option to maintain http session, if you select this option you wouldn't have to worry about extracting the session id. The soapUI guide on this says..
For example, soapUI uses this internally to store an HttpState object in the context when the "Maintain HTTP Session" option has been selected in the TestCase Options dialog.
link to the above line: http://www.soapui.org/Functional-Testing/testcase-execution.html
API description you have attached points out that all you need to do is to manage your cookies correctly.
Successful login response will have the cookie with session ID (also duplicated as a <sessionId>xxxx</sessionId> element in the response).
All you have to do is to include this cookie in all subsequent calls to this API.
Depending on your HTTP/SOAP client these things just need setting up and the client simply follows the contract of HTTP Cookie standard, so it receives cookies, stores them for as long as they are valid, and passes them with all subsequent requests made to the same URI.
If you are using SoapUI, just add session management to your test case as per the picture below:
If that is not enough and you want to pop the bonnet up and see what is what see this blog
HTH

Categories