I need to integrate OpenId connect for SPA application, without having token id in the URL, can we do that?
I'm assuming you have some security concerns with having the ID Token in the URL...
I can see two ways to mitigate risks in this case:
Make sure the OIDC provider redirects to your app using URL fragments instead of via the query string. This ensures that the parameters aren't sent to a server where they might end up in the logs, and should already be the provider's default response mode for implicit flows. If needed you can use response_mode=fragment to enforce it.
You could register a "public" client, but still use the authorization code flow to fetch the ID Token from the token endpoint. In this case you do not present a client_secret to the token endpoint (since the client is public). You could consider using PKCE in this flow as well.
Related
I have gone through multiple blog posts and StackOverflow questions before writing my own. I have multiple queries and none of the posts answer them.
I am using Keycloak Spring Security Adapter to secure my legacy Spring application. I referred to the keycloak documentation here and was able to have OAuth flow running for me. I am using Client Id and Secret as Client Authenticator.
For eg: Access to localhost:8080/about.htm will redirect me to keycloak login screen and after successful authentication, I will be able to view my page. I am also using the below code to read the user details from the token,
KeycloakPrincipal<KeycloakSecurityContext> kp = (KeycloakPrincipal<KeycloakSecurityContext>) auth.getPrincipal();
IDToken idToken = kp.getKeycloakSecurityContext().getIdToken();
user.setUsername(idToken.getPreferredUsername());
Now when I test this application using postman and modify the generated access token, obviously the server gives an error. Ref : How to test application using postman.
However, this is the flow :
Client sends a request to the resource server, resource server checks for a token - if it exists, the client does the validation. If it doesn’t exist or is invalid, it redirects to the authorization server (KC).
My question is,
Who is validating this token? How does postman flow throw an error
if I fiddle with the token?
Do I really need to write a JwtTokenValidator in my application for
each request? Won't that be overkill?
If I use Client Authenticator as Signed Jwt with client secret, will this validation still be required? I am not using it as it introduces latency.
Please assist.
Answer to #1:
When you use any Keycloak adapters in your application (in your case the Spring adapter for Keycloak), that's the one who does the validation and redirects to the login if necessary. As part of the validation, it checks the signature of the token issued by Keycloak. So when you fiddle with the token, the signature doesn't match, hence it throws an error.
Answer to #2
No, you shouldn't need to implement a JwtTokenValidator. The adapter does it for you and a request should reach your endpoint/URL only if it has a valid token. You may only need to do that if you have a special requirements about validating the token (e.g. checking specific claim in the token against some service). Otherwise, you can safely use the claims in the token you received from the KeycloakSecurityContext. You can even setup authorization based on your URL patterns and Keycloak will enforce them too and allow the request to pass if user has necessary roles (like this example).
Answer to #3:
That option only changes the method used to authenticate your app to the Keycloak and has nothing to do with the user's token validation inside your app. In your current setup, when your app wants to communicate with Keycloak (e.g. to exchange auth code with auth token), it authenticate itself to Keycloak with a client-id/client-secret pair (otherwise Keycloak would not know it's your app and will reject the request).
If you choose the "Signed Jwt with Client Secret" option, your client can not just use a client-secret to authenticate to Keycloak. It should support the RFC7523 specification. So it's quite complex in compare with a simple clien-secret approach. In an environment in which you trust your clients (e.g. they're all known apps developed inside the company and you're not going to support public clients to join your Keycloak and use its services) it's quite common and safe to use client-secret approach.
I am developing a REST API using Java Spring Boot framework. Purpose of this API is to connect mobile and web applications so they can work together.
My question is, what are the best practices to develop login functions or the login process. Shall I generate a token or what should I do?
You could follow the best practices as described in OWASP, here.
Most APIs nowadays use token based security. Here are a few guidelines:
You need one service (which is itself public) that authenticates the user.
In order to authenticate the user, it might use a username and a password, and/or other means.
As the result of authenticating the user, this service returns an authorization token.
Your backend should keep track of issued tokens.
Each token will have an expiration time.
Every time the client uses an API, it should send along the token. Usually, the token is sent as an HTTP header.
Every service in the API should validate the token before anything else. If the token is invalid, it should return an appropiate HTTP code.
All communications should be sent over SSL.
OAuth and OAuth2 are two very well known protocols for this very goal. OAuth is a little more complicated than OAuth2.
This is a very high level description, not technically deep, but it should get you started.
I have a web application that provides several rest services (Jersey). Most of the endpoints are secured by BASIC authentification. Further more I use SSL for transport and demand POSTs for every call.
The clients/consumers are android apps.
So far so good. The only service that seems to be vulnerable is the registration. It's the 'first' service to call and a user does not exist yet. So I cannot use OAuth, etc. I also have to keep the endpoint easy accessible to enable the user to regster.
How do I secure this service, so it's not spammed by a bot flooding my database?
How about these?
Use a registration link with a token in the request parameter. Ensure that the tokens expire after sometime. You could create a token endpoint url as well for a client to get a valid token.
Use a custom header or a dynamic custom header in your request. Additionally, you could check for a dynamic custom header to validate the request's authenticity.
Use registration confirmation workflows, such as an email / text verification as soon the registration is done. Run a process every day to delete any user accounts, which are not validated in say x days.
I do not think you can really secure the registration URL in a HTTP way. IMHO, anyone who has the registration url can be a right guy trying to register. So if you ask me, option 3 is better than others.
What is the best way to do authentication and authorization in web services?
I am developing a set of web services, requiring role based access control.
Using metro - SOAP, simple java without EJBs.
I want to Authenticate the user just one time, using username and
password, to be matched against a data base. In the subsequent calls.
I would like to use some kind of session management. Could be some
session id, retrieved to the client at login, to be presented in all
calls.
So Far:
Read authentication using a database - but I want application level validation;
Read application authentication with jax-ws - but i don't want to do the authentication mechanism every time;
I think I can use a SOAP Handler, to intercept all the messages, and do the authorization control in the hander, using some session identifier token, that comes with the message, that can be matched against an identifier saved in the data base, in the login web method.
EDIT:
I still have some questions:
How to know the name of the web method being called?
What kind of token should I use?
How to pass this token between calls?
EDIT 2
Because of #ag112 answer:
I'm using Glassfish.
I use WS-Policy and WS-Security to encrypt and sign the messages. Using Mutual Certificate Authentication. I would like to complement this message level security between applications, with the authentication and authorization for the users also in message level.
I am just developing the services, and I don't know almost nothing the clients, just that they could be created in different languages.
At this point I think the most important thing is to do what ever I need to do to authenticate and authentication the users, I the most easy way to be implemented for the client applications.
#Luis: Here are my inputs.
Well exact solution for your problem depends upon kind of web service clients you expect, do you have control over web service client system, your app server etc.....but assuming you don't have any control over web service client, for you it is just a SOAP message over HTTP transport, here is probable solution.
You can of course performs session management & authentication at message level or transport level. It means either you can have session token and auth token information in SOAP message or you can use standard HTTP Session and HTTP authentication mechanism.
Of course transport level solution is much simpler and industry wide standard in case if transport layer is HTTP. For message level, ws specifications like ws-security can be used.
Your each web service request is simple HTTP GET/POST identified by a unique HTTP URI.
Typically in jax-ws metro environment, WSServlet is one which entry servlet for any web service call and which eventually delegates the call to right service provider implementation class. Since you application is going to be deployed in web server, you can exploit all session and authentication facilities provided by J2ee web container.
Since you are looking for role-based access control, I would use standard <web-resource-collection> in web.xml to specify which role you would like to have in case of particular HTTP URI. You can use standard JAAS login module which can do authentication and populates the JAAS subject with role. If user name/password are provided in SOAP XML, JAAS login module can also search/parse SOAP XML to retrieve those information. JAAS/app server will automatically create auth token and store it as cookie so that each subsequent request need not to go through authentication process again. This is all J2ee standard. You can find plenty of help on internet on this. Please let me know your app server so that I can provide you additional details.
If you still want to use SOAP message level session management, authentication & authorization process, then to provide you more details, may I know more details about your client side.
EDIT1:
Well based on your further inputs, here is my more thoughts:
Message security namely encryption and signature needs to happen each message travels between server and client. where as message authentication- you intend to do once and give a session token/auth token to client for subsequent calls.
Question still remains: if you put a unique session Identifier in SOAP response of first time authentication, do you expect client to parse SOAP response XML and ensure that client should send you session identifier each time in subsequent SOAP requests.
OR
You want to keep session management transparent to client and for client it needs to send username/password token first time and subsequent calls need not require any username/password token. In this case you would need to rely on transport based session management for e.g. HTTP cookies
Now what is the best for you depends upon your use case. Can you tell me what is expected use case flow? how another system (web service client) makes more than one service call to your system? Is another system user driven/some background process? What is exact need that you want only first service call to go through authentication process not subsequent calls?
PS: Glassfish server provides a way of configuring message authentication provider which automatically enables/disables message level authentication.
EDIT2:
I understand you do not want to store user credentials in client app and web service server need those user credentials.
OAuth is open standard protocol which allows site A to access user's private data on site B. Ultimate idea is site A gets auth token which has specific expiry time. So Token containing encrypted from of user credentials or jsession id help you avoid need of re-authentication. You only need to decide where you want to keep token at client app side
You can keep token as cookie if transport is HTTP protocol.
Having said that ofcourse passing user credentials each time seems bit easier and straight forward.
You can also go for OpenEJB.
It used JAAS with WS-Security.
I hope the link is useful.
After all the help, I create this answer to simplify, and summarize all the ideas that was discussed.
The questions has 2 requisites:
Message level security;
One time authentication.
With ag112 help, this is hard to do, or to elegant in any way. So here are to conclusions:
For message level security send the user
credentials every time (place it in SOAP header);
For one time authentication use transport level security, and do a
session management.
I prefer the first one, because the message level was the biggest requisite.
As had no answers, following #unhillbilly advise, I answer my own question, with the progress so far:
How to know the name of the web method
being called;
Using a SOAP handler, finding the name of the first element in the body.
What kind of token should I use;
I decide to use a 128 bits token, representing each session. The Webservices, continue to be session-less, the key is just for authorizations purposes.
How to pass this token between calls.
For the login web method the result has the token, in each subsequent calls, the token is a parameter.
is there a better answer?
I'm hosting a REST web service in a Grails application, using Spring Security, i.e.:
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def save = {
println "Save Ride REST WebMethod called"
}
I'm calling it from an Android app. (Calling the unsecured service works just fine.)
To call the service, I'm manually building up a request (HttpUriRequest) and executing it with an HttpClient.
I'm wondering what the best practices are, and how to implement them... Specifically, should I:
Perform a login once, to retrieve a JSESSION_ID, then add a header containing it into the HttpUriRequest for each subsequent request?
Or (not sure how I would even do this) include the login and password directly on each request, foregoing the cookie/server-side session
I think I can get option 1 working, but am not sure if Spring Security permits (2), if that's the way to go... Thanks!
--also, there isn't any library I'm missing that would do all this for me is there? :)
Spring security does support both basic authentication and form based authentication (embedding the username/password in the URL).
A REST service is generally authenticated on each and every request, not normally by a session. The default spring security authentication (assuming you're on 3.x) should look for basic authentication parameters or form parameters (j_username and j_password) (in the form http://you.com/rest_service?j_username=xyz&j_password=abc).
Manually tacking the j_username/j_password onto the URL, adding them as post parameters (I believe), or setting the basic authentication username/password should all work to authenticate a REST service against the default Spring Security interceptors, right out of the box.
I will admit that I haven't tried this on REST services, though I do clearly recall reading exactly this in the docs as I did the same for basic page logins on spring security recently. Disclaimer over.
I think you can use a login-once-and-get-a-token method that's similar to how oauth works.
sending username and password across the network outside of secured channel(https/ssl) is a terrible idea. anyone on the network can sniff your request package and see the clear text password.
on the other hand, if you use a token method, since the token string is randomly generated, even the token is compromised, the worst case is someone can use the token accessing your REST API.
another solution is going through ssl tunnel(HTTPS). i have actually done a comparison and result shows: 80 requests/min(https) vs 300 requests/min(http)