Restlet: Adding a role depending on which 'project' (group) the user is accessing - restlet

Assume a blackboard type application. There are 2 Projects - ProjectA and ProjectB. User 'nupul' (me) is part of both projects. For A I'm an admin and for B I'm just a 'member' (no admin rights)
When accessing the resource at /MySite/ProjectA/Items I want to check if the user is an admin or not.
I know it can be simply done by picking out the {projectName} parameter from the request and using the identifier (of the user making the request) and forwarding that to check against a DB etc.,
My question is 'how' can I add the roles using an Enroler 'during' authentication itself. Since I don't have access to the {projectName} parameter at that stage. I don't know if you have to use Groups/Realms etc., to make this work, but honestly it's just taking me tooooooooooooooooooo long to even understand how to effectively use this? (i.e., before the request is forwarded to the resource)
I mean I know I can create these groups/realms but how do I access the correct 'role' from the resource???? Restlet seriously needs to have more realistic examples and a much better documentation showing the use of it's classes!! It's driving me insane!! Authentication shouldn't be THIS DIFFICULT! :)

The way to do what you want is to split your routers basing on project name within your application (method createInboundRoot). In this case, the projectname will be evaluated before calling the authenticator. See below some examples of implementing such approach:
public Restlet createInboundRoot() {
Router rootRouter = new Router(getContext());
rootRouter.setDefaultMatchingMode(Template.MODE_STARTS_WITH);
rootRouter.attach("/{projectname}/", createApplicationForProject());
return rootRouter;
}
private Restlet createApplicationForProject() {
Router router = new Router(getContext());
ChallengeAuthenticator guard
= new ChallengeAuthenticator(getContext(),
ChallengeScheme.HTTP_BASIC, "realm");
guard.setVerifier(verifier);
guard.setEnroler(enroler);
guard.setNext(router);
router.attach("items", ItemsServerResource.class);
return guard;
}
Using such approach, you'll have access to the value of the projectname variable within the verifier and be able to use it in the authentication processing.
Hope it helps you,
Thierry

Related

Session lost after redirect SAML: may be different webapps?

I am fairly new to webapps programming, so I thought of asking here.
I am implementing the SAML2 protocol in an open source app (namely OFBiz) but I am encountering a problem related to session loss after the protocol made its course.
I am following these steps to implement the protocol. Suppose ofbizwebsite.com is the URL of the site.
Installed a custom plugin named SAMLIntegration which exposes the ACS page and the logic for login. To my understanding, a plugin (gradle) is like an indipendent java project, which translates to a new set of resources for the application (the plugin enables, for example, to visit ofbizwebsite.com/SAMLIntegration and setup some resources).
Exposed the ACS page to ofbizwebsite.com/SAMLIntegration/control/acs, as well as metadata ofbizwebsite.com/SAMLIntegration/control/metadata.jsp
Created the logic for login. Basically, an entity called UserLogin is saved in the session and recovered by a "checker" to understand if an user is logged in. Suppose that this checker is a HTTP WebEvent handler which can be called by any resource requiring authentication.
Now, the problem. If redirect the user to a resource on SAMLIntegration (for example ofbizwebsite.com/SAMLIntegration/control/aview or any ofbizwebsite.com/SAMLIntegration/control/* by calling response.sendRedirect("aview")) check works and login is preserved. Visiting any resource (for example ofbizwebsite.com/aplugin/control/anotherview) by navigating the application does not preserve the session.
OFBiz use internally a mechanism for preserving the userLogin between webapps, by creating an HashMap between and UUID and a UserLogin object. The UUID is passed between two different resources, appending this key to each path (so ofbizwebsite.com/aplugin/control/anotherview?externalKey=THEEFFECTIVEUUID)
To my understanding, changing from ofbizwebsite.com/SAMLIntegration/control/* to ofbizwebsite.com/aplugin/control/* determine a session loss. So, my idea was to replace the UUID mechanism with SAML2. However, I do not know how to solve this problem.
In particular, I would like to execute a SAML request each time the checker function is executed. If I can't find the user in the session, a SAML request is fired. However, my problem is HOW to manage the response. Normally, I would redirect it to the acs ofbizwebsite.com/SAMLIntegration/control/acs. Doing so, however, does not allow me to handle the response in the checker function, as the control is passed to another servlet by an external request (the SAML response fired by the IdP). Should I provide a different acs for each different path? (so one for SAMLIntegration and one for aplugin?) And, even if this was the case, how can I return the control to the checker function which has invoked the SAML request?
Here you go for installing the Shibboleth HTTPD module: https://pad.nereide.fr/SAMLWithShibboleth
You also need this method somewhere in OFBiz (I recommend LoginWorker.java, but you can put it where you want). It allows to use the externalAuthId of the userLogin for authentication, with the uid returned by the sso:
public static String checkShibbolethRequestRemoteUserLogin(HttpServletRequest request, HttpServletResponse response) {
LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
Delegator delegator = dispatcher.getDelegator();
// make sure the user isn't already logged in
if (!LoginWorker.isUserLoggedIn(request)) {
String remoteUserId = (String) request.getAttribute("uid"); // This is the one which works, uid at Idp, remoteUserId here
if (UtilValidate.isNotEmpty(remoteUserId)) {
//we resolve if the user exist with externalAuthId
String userLoginId = null;
GenericValue userLogin;
try {
List<GenericValue> userLogins = delegator.findList("UserLogin",
EntityCondition.makeConditionMap("externalAuthId", remoteUserId, "enabled", "Y"),
null, null, null, true);
userLogin = userLogins.size() == 1 ? userLogins.get(0) : null;
} catch (GenericEntityException e) {
Debug.logError(e, module);
return "error";
}
if (userLogin != null) {
userLoginId = userLogin.getString("userLoginId");
}
//now try to log the user found
return LoginWorker.loginUserWithUserLoginId(request, response, userLoginId);
}
}
return "success";
}
You also need to have this method as an OFBiz preprocessor in the webapp controllers. I suggest to have a look at common-controller.xml.
Finally you need the configs that redirect to the SSO page if no session. That should do the job, at least it works for them...
Finally I recommend https://www.varonis.com/blog/what-is-saml in case of need.

How to get session context in wamp router validator

According to comment and a criticism for question being too broad; I'll try to make it more specific;
Environment - Server: autobahn|python with twisted, wampv2
Given that:
a) I have a class which extends RouterSession and authenticates user, and at the moment of authentification knows who the user accessing the wamp service is;
and
b) I have a class which extends ApplicationSession and on creation exposes several rpc methods through wamp
How do I access the user data in the exposed RPC method. By the user data - I mean - which I verified at the beginning of a specific client connection through RouterSession.
Because ApplicationSessions are initiated only once, and don't have a clue about caller (from what I have seen in debugger).
The reason I would need this - is to execute the rpc call with the context of a calling user. Where method's result might depend on specific user profile properties.
I am probably looking for something which could represent per-connection created Application instances (which could then hold reference to authorization result and data). Like most of the server Protocols operate in twisted.
-----------------ORIGINAL POST-----------
Brief question: imagine a scenario where user rights are based not on method but object; Example - I may have right to edit my profile account and profile accounts of my subordinates but not any other. This leaves to a situation where I would expose "com.myorg.profile.update_profile_details" RPC through WAMP to everyone, but would have to check which user is trying to modify which profile.
I see there is a validate mechanism in WAMP Router to deal with validating request - but it seems, that it lacks a reference to previous authentication result or session.
I really would like to avoid passing session keys (or, god forbid auth tokens) back and forth through the WAMP; whats the suggested approach for this?
----------------END OF ORIGINAL POST----------
After debugging traces back and forth, I found a solution which fits me - the trick is to pass additional options parameter when registering RPC methods:
self.register(self.test_me_now, 'com.ossnet.testme', options = RegisterOptions(details_arg = 'details', discloseCaller = True))
and voila - there is a new incoming parameter into registered RPC method: 'details'
with following contents:
CallDetails: CallDetails(progress = None, caller = 774234234575675677138, authid = johan.gram, authrole = user, authmethod = ticket)

Apache Shiro - issue with isPermitted() method and wrong Authorizer class

We have implemented a class called AuthorizerImpl that contains two objects: an AuthorizingRealm and a Subject. We have implemented an isPermitted() method which subsequently calls the isPermitted() method on the subject. Our code looks something like this:
// UserContext object uc is passed in here
AuthorizerImpl auth = new AuthorizerImpl(uc.getUser());
auth.isPermitted("winnebago:drive:eagle5");
We initially log in and authenticate a user's permissions using the above code. The first time a user logs in, it is a a "base user" so to speak. There are certain screens that are specific to certain users, so we call the above code again with a different uc.getUser() to verify the new users permissions. What I am seeing though is that the backend Shiro code is using the previous user to check the permissions, not the new user that I passed into the isPermitted() method. Each time we are calling "new AuthorizerImpl(uc.getUser())" we are creating a new Subject and AuthorizingRealm that are instance variables inside the AuthorizingRealm object. It was my impression that when I create a new AuthorizerImpl, it should use the new subject and realm that we are creating in the constructor. However, it seems that Shiro is caching the previous realm object that was used and is using that? We are using the DefaultSecurityManager. After doing some debugging, I noticed that the DefaultSecurityManager has an authorizer instance variable. It appears to be using the first authorizer object and not the new one that should be created with the new user, which leads me to believe it is is being cached. Is there a way to turn off this caching? Is this what is happening or is it something else? The permissions are being retrieved correctly from the database if the correct user is used to check. How can I resolve this?
Thank you in advance.

How do I bind the current user session to a dynamic var using Clojure Friend library?

I am using the Friend Authentication Library for Clojure to add HTTP basic auth to my webapp.
I have a set of database access functions in a db.clj module that abstracts away the current user so I can invoke methods like (db/get-item ...) for example to retrieve an item for the current user without explicitly specifying the user. I do this by defining a dynamic var called *username*. This allows me to easily test the database access functions at the REPL for different users, then the webapp code can rebind *username* to the session user for when it calls the db functions.
I need to bind *username* to the user for the current session so that whenever the functions in db.clj are accessed from a web server request, the *username* var is set properly.
I can get the session username from ((friend/current-authentication) :username) but I can't figure out where I can hook this into the web-server code. I have a simple middleware:
(defn wrap-username [app]
(fn [req]
(binding [*username* (friend/current-authentication :username)]
(app req))))
But no matter where I call this middleware from, current-authentication always returns nil.
I am trying to understand how the friend authentication code works in order to determine the correct place to do my binding but so far I haven't figured it out.
I guess the way you are calling current-authentication is incorrect as the documentation says you need to pass the current request to this function, so it should be something like:
(binding [*username* ((friend/current-authentication req) :username)] ...
Also make sure the friend middleware is applied before your username middleware.

Rest and ZF session management

I'm trying to create a web service which utilizes Zend framework. The API is REST based and uses Zend_Rest_Controller as base class. I wish to have user management and session, and for that I'm using the following code:
Login (POST)
// user id and password fetched first
$users = new Application_Model_DbTable_UserInfo();
$auth = Zend_Auth::getInstance();
$authAdapter = new Zend_Auth_Adapter_DbTable($users->getAdapter(),'users');
$authAdapter->setIdentityColumn('userid')
->setCredentialColumn('password');
$authAdapter->setIdentity($userid)
->setCredential($pwd);
$result = $auth->authenticate($authAdapter);
if($result->isValid()){
Zend_Session::rememberMe(604800);
$storage = new Zend_Auth_Storage_Session();
$usa = $authAdapter->getResultRowObject();
$auth->getStorage()->write($usa);
$authSession = new Zend_Session_Namespace('Zend_Auth');
$authSession->setExpirationSeconds(60*60);
}
and when accessing the service with e.g. some GET method I wish to check that there is a valid session with the following code:
$auth = Zend_Auth::getInstance();
if(!$auth->hasIdentity())
{
// error handling etc.
}
I never get an identity, hence the service doesn't work.
I have followed the guidance for ZF authentication quite strictly, but does the REST stuff need additional items to be taken into account?
I know I'm not answering your question, but if you are REALLY planning to implement a true REST interface (which implies it's going to enable you to scale well), you'd probably better forget about sessions and using Zend_Auth in the way you've depicted above.
Take a look here, where something about REST interfaces and authentication has been discussed already:
Can you help me understand this? "Common REST Mistakes: Sessions are irrelevant"
In short, quoting from the Q/A thread above, "To be RESTful, each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP". I really feel like seconding that.