package org.dcache.services.login; import org.springframework.beans.factory.annotation.Required; import javax.security.auth.Subject; import java.security.Principal; import java.util.Set; import diskCacheV111.util.CacheException; import diskCacheV111.util.TimeoutCacheException; import dmg.cells.nucleus.NoRouteToCellException; import org.dcache.auth.LoginReply; import org.dcache.auth.LoginStrategy; import org.dcache.cells.CellStub; public class RemoteLoginStrategy implements LoginStrategy { private CellStub _stub; public RemoteLoginStrategy() { } public RemoteLoginStrategy(CellStub stub) { setCellStub(stub); } @Required public void setCellStub(CellStub stub) { if (stub == null) { throw new NullPointerException(); } _stub = stub; } public CellStub getCellStub() { return _stub; } @Override public LoginReply login(Subject subject) throws CacheException { if (_stub == null) { throw new IllegalStateException("CellStub is not set"); } try { LoginMessage message = _stub.sendAndWait(new LoginMessage(subject)); return new LoginReply(message.getSubject(), message.getLoginAttributes()); } catch (CacheException e) { /* Note that dCache vehicles can transport errors. These * are re-thrown as a CacheException (or subclass thereof) * with a corresponding return-code value. The * return-code exists to support legacy code; subclassing * CacheException is more correct. * * Some exceptions, if thrown by the remote cell, will be * translated to the generic CacheException class. In * particular, if IllegalArgumentException is thrown then * the generic CacheException will be thrown with * return-code CacheException.INVALID_ARGS. * * LoginStrategy classes are expected to throw * IllegalArgumentException when presented with a Subject * they structurally do not support; however, remotely * throwing IllegalArgumentException will be mapped to * CacheException, so breaking the LoginStrategy contract. * * Here we map a generic CacheException with return-code * CacheException.INVALID_ARGS to * IllegalArgumentException. */ if (e.getRc() == CacheException.INVALID_ARGS) { throw new IllegalArgumentException(e.getMessage(), e); } else { throw e; } } catch (NoRouteToCellException e) { throw new TimeoutCacheException(e.getMessage(), e); } catch (InterruptedException e) { throw new CacheException("Login failed because the operation was interrupted"); } } @Override public Principal map(Principal principal) throws CacheException { if (_stub == null) { throw new IllegalStateException("CellStub is not set"); } try { return _stub.sendAndWait(new MapMessage(principal)).getMappedPrincipal(); } catch (InterruptedException e) { throw new CacheException("Login failed because the operation was interrupted"); } catch (NoRouteToCellException e) { throw new TimeoutCacheException(e.getMessage(), e); } } @Override public Set<Principal> reverseMap(Principal principal) throws CacheException { if (_stub == null) { throw new IllegalStateException("CellStub is not set"); } try { return _stub.sendAndWait(new ReverseMapMessage(principal)).getMappedPrincipals(); } catch (InterruptedException e) { throw new CacheException("Login failed because the operation was interrupted"); } catch (NoRouteToCellException e) { throw new TimeoutCacheException(e.getMessage()); } } }