I have a client - server application which uses cxf DOSGi [1]. Now I want to authenticate the clients from the server and create a session for the client. The client will have a cookie which is used to access the service once authenticated. I would like to know what is the best way for the server to access the HTTP session and the best way to store a cookie at the client end once authenticated.
I was thinking of making a custom Session object at application level once authenticated and send a Cookie object to the client. So when the client accesses the service methods, it will pass the cookie as an argument. The client will be validated in every service method. But I dont think this is the best way to handle this since every service method must have a separate argument to pass the Cookie.
I came across this when I was googling [2]. Is it possible to get "WebServiceContext" in the service in DOSGi? Even if I get it, how would I store the cookie at client end and make sure the client sends the cookie in every subsequent web service call?
[1] http://cxf.apache.org/distributed-osgi-greeter-demo-walkthrough.html
[2] How can I manage users' sessions when I use web services?
Any help is highly appreciated.
Thanks.
You can use a custom intent to control authentication. Basically an intent is a CXF feature that is applied to the webservice by DOSGi. You create the feature in a separate bundle and then publish it with a special property for its name: See the DOSGi reference guide.
In a project we created a feature that read a threadlocal containing the authentication context and used the credentials stored there to populate the CXF authentication. So you just have to store the credentials once into the threadlocal at the start of you application and all calls work.
Currently there is no simple documenation or example for this case but I plan to create it in the near future as authentication is a common problem. I plan to use shiro as an authentication framework and write a generic adapter for CXF. I will add a comment or another answer as soon as I got it ready. In the meantime you can try to do the same yourself.
Related
I am working on a project where I need to create an application that shall act as an OIDC mediator between a client which only supports OIDC for authentication and a REST api. The REST api is able to generate tokens and give user info but does not support OIDC.
To achieve this I am thinking of using keycloak to handle the OIDC communication with the client and implement my own java application that keycloak can trigger to realize the authorization, token and userinfo endpoint (sort of a custom ownmade identity provider) handling the communication with the rest api.
I have created a realm in keycloak and configured the realm to use an Identity Provider Redirector with an Identity Provider I added in keycloak (user-defined OpenID Connect v1.0). In the identity provider configuration I have set all the URLs to point to my java application but the initial OIDC authorization call from the client just redirects to the redirect_uri with a #error=login_required without any of my endpoints in the java application beeing triggered.
I guess there is something I have missed.. I need to intervene the authorization flow so that I can pick up a query param from the authorization request that needs to be handled in my java application. I also need to map the token from the rest api into the token request (when this request comes from the backend of the client app), and finally map the userinfo object as a response to the userinfo request.
I really hope someone have time to point me in the right direction. Thank you so much in advance.
Edit:
I have added a sequence diagram to explain it better:
I need to intercept the authorization request call to pick up a custom query param (endUserString) that identifies the user. There will be no user login form. I need the param in my code that uses this towards the REST API. Both the token and the userinfo must be received from my APP and not from keycloak itself.
The Java Mediator may ask for a token in advance (A) and use this to access the Rest API (using a predefined clientId and clientsecret). Alternatively this token may be fetched for each method. To token must be used to retrieve customer info from the REST API (B). I want to wrap this with OIDC support without any login form. A browser will just redirect to the authorization flow with the endUserString identifying the end user. The customer info will be returned from the java mediator into keycloak responding this in the GetUserInfoRsp.
I think there might be a simpler solution than what you envisioned: implementing your own custom authenticator for Keycloak.
Keycloak has a notion of authentication flow which is a tree of authenticators than are provided by Keycloak or custom made. Each authenticator can be called to try to authenticate the user.
The most common one is the Username/Password Form which displays a login page to the user and authenticates the user if the provided credentials are valid. But you could imagine any type of authenticator such as an SMS authenticator or a magic link one.
You can find the existing Keycloak's authenticators on their repo and the documentation on how to create your own here.
In your case, you would need to implement your own logic where your authenticator would get the endUserString param from the request and call the REST API to validate the user's identity. You could fetch the REST API token at initialisation or for each request. You could also modify the user stored in Keycloak with data coming from the REST API's user info endpoint (common OIDC attributes or custom attributes).
Please note that the dev team announced Keycloak X, a sort of reboot of the project which will probably bring breaking changes to their APIs.
Also, please consider all the security impacts of your design as, from what you provided, it seems the authentication of a user will only rely on a simple query parameter which, if it doesn't change over time for example, feels like a big security hole.
What is the correct way for a java heavy client to authenticate with an OpenAM protected servlet?
Java openAM sdk exists, which I have used and it does provide access to the SSO Token. Where things break down is when this same heavy Java client attempts to send serialized objects to a protected tomcat 7 (tomee+) servlet using this SSO Token id as a cookie. The OpenAM filter uses redirection with an embedded / hidden form containing credentials. This breaks the serialized object communications.
So what is the right way to have a Java heavy client authenticate such that it can then send serialized objects back and forth to a protected servlet? Is this even possible?
There are several ways to authenticate a client:
use the REST API to authenticate the client (/identity/authenticate or /json/authenticate)
using the ClientSDK AuthContext API
sending POST requests to /UI/Login (not necessarily the best way..)
After acquiring the token the only thing you have to make sure of is that you send the session cookie to the protected pages. In case you receive a self-submitting form for JAAS, then that means that you are using the agent in J2EE_POLICY or ALL mode and Java EE declarative security is enabled. Possible solutions for this problem area:
modify the client so it copes with the JAAS FORM login content (i.e. grab the input values and perform a POST manually), after this possibly you will also have to send the JSESSIONID with all your requests.
consider removing protection for your servlets in web.xml, that way the container will not attempt to display the JAAS login form, but then this will also mean that you won't have the fancy JAAS integration either (isUserInRole/getRemoteUser/#RolesAllowed/etc)
move your servlet to a separate application, which can be protected in a different agent filter mode (URL_POLICY/SSO_ONLY), it would be still protected, but again without the JAAS integration..
Basically I can't think of an easy way of leveraging JAAS integration with the use of a heavy client without dealing with form based login.. At one point in time I was able to implement a Java EE application client that authenticated into the container's (agent's) realm using programmatic login and that worked, but I don't suppose your heavy client is actually a Java EE application client..
I have an external SOAP web service that attaches to our services layer inside the application. For the Web 2.0 application, the services layer uses the session to store the user's "key chain" or the things a user can do in the system.
Now I'm trying to figure out how to do the same thing with my web service client to our services layer. The problem is that the web service URL can't contain a cookie that holds the session ID. (If I'm wrong, please say how and I'll do it that way.)
When the web service client connects the first time, I require a login and generate a security key that uniquely identifies that user and will expire within a certain period requiring them to login again.
I'd like to find a way in my endpoints to re-attach to the proper session for that security key and then the security will work automatically.
My endpoints are currently being served from tomcat.
How can I get there from here?
All input appreciated.
I ended up using REST to come back into our webapp through the URL so that I have a session. I connected to it that way.
I've got a j2ee web application using j2ee security, so the identity of the user is propagated from WebSEAL to the application, running in WAS7. I'm now trying to make a SOAP webservices call and propogate the user identity in that webservices call. To do this, I grab the LTPA (WSCredential) and LPTA2 (SingleSignOnToken) using the WSSubject calls and attach them to the webservices call using.
bp.getRequestContext().put(Constants.REQUEST_TRANSPORT_PROPERTIES,sendTransportHeaders);
where bp is my BindingProvider. This all should work. But when I make a webservices call, I get back this exception.
Cause =java.io.IOException: Unable to deserialize the Subjects in this Context
I looked at the fields within the LTPA token and all seems right (same realm between the token and the j2ee security realm webservice I'm calling, the token is forwardable, etc), and I cannot find much about this error online, except for (what seems to be an unrelated) case when trying to pass it into the EJB and one case where the realms don't match.
Any ideas? Thanks.
Can you state clearly as to what you are trying to do here?
You should be able to pass the LTPA tokens across transparently with just configuration instead of trying to write some code to achieve the same.
The Web Applications making the Web Service calls to another WebSphere server.
have a quick read at this.
http://www.ibm.com/developerworks/websphere/techjournal/0607_desprets/0607_desprets.html
Things in WAS7 should be very similar to WAS V6.
HTH
Manglu
#jeffsix: are you trying to make a webservice call from application running in one websphere server to another application in another websphere server? Make sure LTPA keys are same on both server.
I am building a RESTful Webservice using Apache Jersey. Now I want that you need an authentication for some requests to it. Using the typical REST-approach the Authentication should be done via HTTP-Authentication. But a post here mentions that a better way how this can be done is by using cookies. I think there are some valid points in the discussion. (How) Can I make my Jersey Authentication work with Cookies? Do I need another framework for it?
Jersey uses the authentication mechanism declared in the enclosing web application's web.xml, practically either HTTP Authentication (over SSL) or Form-based Cookie authentication.
If you want to used cookie-based session authentication, users must authenticate with the web service first to create a session which can be used to check their identity for future calls. The servlet spec provides a standardized way to authenticate using cookies and session using a web form, which however, is not compatible to a web service type of application. So you would probably want to cook up some custom solution to let users submit their credentials via POSTing an XML or JSON document. A problem with this method is that if a user performs a call to a resource without first authenticating or after the session has expired, they will need to be redirected or receive some type of error code. Not impossible but it adds complexity to your web service.
At this point you have to wonder if using HTTP Auth is not the better choice for web service style apps. We recently built a web service using Jersey and HTTP Auth as the authentication mechanism. We then build a Javascript front end on top of it. The Javascript client always submits the Authentication headers to the web service so that the user is never confronted with the HTTP Auth authentication window from the browser. Perhaps the best of both worlds.