Archived

This forum has been archived. Please start a new discussion on GitHub.

How to get current user in servant object's method?

Hi, I use Glacier2 as router, and develope a client program to login the router to locate the servant object in order to invoke it's method. Now I need to get the current user in the method, will anybody help me how to?

thanks.

Comments

  • benoit
    benoit Rennes, France
    Hi,

    You can use Glacier2 sessions to keep track of the user Id. See the Glacier2 demos included with your distribution for some examples (in the demo/Glacier2 directory). Let us know if you need more information.

    Cheers,
    Benoit.
  • Thanks for your reply.

    I had find a way to resolve this problem, but I don't know it's OK or not, so I share it to the public:

    (1)At the server site, start a SessionServer program for Glacier2Router to validate the login user, if the user login OK, then store User_ID and Session_ID to a Database(or a shared cache), and here is my Java code:
     public final class SessionManagerI extends Glacier2._SessionManagerDisp {
    	private Log logger = LogFactory.getLog(SessionManagerI.class);
    
    	public Glacier2.SessionPrx create(String userId,
    			Glacier2.SessionControlPrx control, Ice.Current current) {
    		logger.info("creating session for user: " + userId);
    		Glacier2.Session session = new SessionI(userId);
    		SessionPrx sessionPrx = Glacier2.SessionPrxHelper
    				.uncheckedCast(current.adapter.addWithUUID(session));
    		String session_id = sessionPrx.toString();
    		System.out.println(session_id);
    		DbUtil.store(userId,sessionId);
    		return sessionPrx;
    	}
    }
    
    (2) At client Site, when client success to login and acquire the instance of Glacier2.SessionPrx, put Session_ID to DefaultContext, and Here is my Java Code:
         session = routerPrx.createSession(this.connectInfo.getUserName(),
                                                this.connectInfo.getPassword());
         Map<String, String> ctx = new HashMap<String, String>();
         ctx.put("session_id", session.toString());
         this.communicator.setDefaultContext(ctx);
         log.log("success to login router");
    

    (3) At the server site, when client application send a invoke request to the Servant's method, it will auto send Session_ID to the server, the server application now can acquire Session_ID, and then query the database to find out the login user. Here is my code:
    	@Override
    	public List<BundleInfo> findAll(Current __current) {
    		System.out.println(__current.ctx.get("session_id"));
    		String userId=DbUti.findLoginUser(__current.ctx.get("session_id"));
    		Bundle[] bundles = Activator.getInstance().getContext().getBundles();
    		List<BundleInfo> bundleInfos = new ArrayList<BundleInfo>();
    		for (Bundle bundle : bundles) {
    			BundleInfo bi = new BundleInfo();
    			bi.setBundleSymbolicName(bundle.getSymbolicName());
    			bi.setVersion((String) bundle.getHeaders().get("Bundle-Version"));
    			bi.setStatus(bundle.getState());
    			bundleInfos.add(bi);
    		}
    		return bundleInfos;
    	}
    
    (4) When client program logout, remove Session_ID from SessionI's destroy method:
    public final class SessionI extends Glacier2._SessionDisp {
    	private Log logger = LogFactory.getLog(SessionI.class);
    	private String _userId;
    
    	public SessionI(String userId) {
    		_userId = userId;
    	}
    
    	public void destroy(Ice.Current current) {
    		logger.info("remove session which id is: " + _userId);
    		DbUti.remove(userId);
    		current.adapter.remove(current.id);
    	}
    
    }
    

    I had tested it this morning(Beijing Time Zone), and it seems that everything is OK, but Communicator.setDefaultContext is deprecated, what method should I use, and how?

    Thanks.
  • Let us know if you need more information.
    I succeed to develope a client GUI program for our company to manage the OSGi bundles deployed at IceGrid nodes, and here is the screen copy.

    This is a Eclipse RCP application using Ice as communication layer. It has the folowing features:
    (1) start/stop/restart bundle.
    (2) group bundle.
    (3) view log file.
    (4) config the bundle's runtime parameter and restart it.
    (5) upload bundle to remote server(not implement).
    (6) permission check(not implement).
  • benoit
    benoit Rennes, France
    Hi,

    You can use implicit contexts as a replacement for setDefaultContext, see here in the Ice manual for more information on implicit contexts.

    Instead of passing the session id in the request context, why don't you just pass the user id? I suppose it's to ensure that another client can't steal the identity of another client? While using a UUID is safer, it could still be guessed (see this recent thread). If you want to make sure this can't happen, a better approach would be to setup a servant per session on the server side, this servant would cache the user ID and would not rely on any client hints to retrieve it.

    Cheers,
    Benoit.
  • The user_id is very simple, for example, we often use root as user_id, it's easy to guess.

    It seems that UUID generator is not safe since it can be guessed.
    Now I use another UUID genrator:
    public final class SessionManagerI extends Glacier2._SessionManagerDisp {
    	private Log logger = LogFactory.getLog(SessionManagerI.class);
    	private final static String anotherPassword = "1234abc";
    
    	public Glacier2.SessionPrx create(String userId,
    			Glacier2.SessionControlPrx control, Ice.Current current) {
    		logger.info("creating session for user: " + userId);
    		Glacier2.Session session = new SessionI(userId);
    		long timestamp = Calendar.getInstance().getTime().getTime();
                             //Use MD5 the generate it!
    		String objectId = MD5.encode(anotherPassword + timestamp);
    		SessionPrx sessionPrx = Glacier2.SessionPrxHelper
    				.uncheckedCast(current.adapter.add(session, current.adapter
    						.getCommunicator().stringToIdentity(objectId)));
    		String session_id = sessionPrx.toString();
    		System.out.println(session_id);
    		// DbUtil.store(userId,sessionId);
    		return sessionPrx;
    	}
    }
    

    I test it and it is OK. I use MD5 to encode the timestamp and another password, now you can guess the timestamp, but you can't the generate MD5 code, so I think it's safe.

    If MD5 is not safe, I can use RSA to replace it:
    (1) At the server site, the server program use it RSA PRIVATE KEY to encode a timestamp, and use the encoded string as object_id which can be transform to Session_ID.
    (2) At the client site, the client program use server's RSA PUBLIC KEY to validate the object id.
    (3) When client send object id back to the server, the server can also validate the object id.

    So, now do you think is OK?
  • benoit
    benoit Rennes, France
    UUIDs generated by the Ice runtime can't easily be guessed so you can continue using them. My point was that sending this UUID (or MD5 token) over the wire is still less secure than not sending it at all :) (it could be intercepted by a network sniffer for example).

    By using per-session servants on the server side and appropriate Glacier2 filtering, you can have the guarantee that only the client which established a given session is invoking on a given Ice object.

    Cheers,
    Benoit.