/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation: version 3 of * the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package org.ow2.proactive.resourcemanager.authentication; import java.io.Serializable; import java.security.Permission; import java.security.PrivilegedAction; import javax.security.auth.Subject; import org.objectweb.proactive.api.PAActiveObject; import org.objectweb.proactive.core.UniqueID; import org.objectweb.proactive.core.body.UniversalBody; import org.objectweb.proactive.core.body.proxy.BodyProxy; import org.objectweb.proactive.core.body.request.Request; import org.objectweb.proactive.core.mop.Proxy; import org.objectweb.proactive.core.mop.StubObject; import org.ow2.proactive.authentication.crypto.Credentials; import org.ow2.proactive.authentication.principals.UserNamePrincipal; import org.ow2.proactive.resourcemanager.core.history.UserHistory; /** * This class represents a client of the resource manager(RM). * It could be an internal service or connected remote user. * * The class is used to track and associate all activities inside the RM to particular user. * * It also provides capabilities to detect if the client is still alive. * * NOTE: The pinger functionality has some drawbacks and limitations. For instance it cannot be used * after serialization/deserialization of the class. It relies on ProActive internals and * probably will be replaced in the future. * */ public class Client implements Serializable { /** The security entity that represents this client */ private final Subject subject; /** Defines if this client has to be pinged */ private final boolean pingable; /** Client's name */ private String name; /** Unique id of the client */ private UniqueID id; /** * URL of the client */ private String url; /** Body of the sender of request */ private transient UniversalBody body; /** User connection history stored in the data base*/ private transient UserHistory history; private Credentials credentials; public Client() { this.subject = null; this.pingable = false; } /** * Constructs the client object from given client subject. * @param subject with the name of the client authenticated in the resource manager (can be null) * @param pingable defines if client has to be pinged */ public Client(Subject subject, boolean pingable) { this.subject = subject; this.pingable = pingable; if (subject != null) { UserNamePrincipal unPrincipal = subject.getPrincipals(UserNamePrincipal.class).iterator().next(); this.name = unPrincipal.getName(); } if (pingable) { Request r = PAActiveObject.getContext().getCurrentRequest(); this.id = r.getSourceBodyID(); this.url = r.getSender().getNodeURL() + "/" + this.id.shortString(); this.body = r.getSender(); } } /** * Gets the name of the client * @return the name of the client */ public String getName() { return name; } /** * Gets the id of the client * @return the id of the client */ public UniqueID getId() { return id; } /** * Sets the id of the client * @param id new client's id */ public void setId(UniqueID id) { this.id = id; } /** * Defines if the client has to be pinged. * Client of the core could be an internal service * or connected active object. We heed to ping only connected * ones. * * @return true if ping is requires */ public boolean isPingable() { return pingable; } /** * Redefined equals method based on client's name */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Client client = (Client) o; if (name != null ? !name.equals(client.name) : client.name != null) { return false; } return true; } @Override public int hashCode() { return name != null ? name.hashCode() : 0; } /** * @return string representation of the client */ public String toString() { return "\"" + name + "\"" + (id != null ? " (" + url + ")" : ""); } /** * Checks if the client is alive by sending the message to it. * There is a blocking network call inside so it should be used carefully. * * Throws an exception if the client body is not available which is * always the case after serialization. * * @return true if the client is alive, false otherwise */ public boolean isAlive() { if (pingable) { if (this.body == null) { throw new RuntimeException("Cannot detect if the client " + this + " is alive"); } try { return PAActiveObject.pingActiveObject(this.body); } catch (Exception e) { return false; } } return true; } /** * Extract the body id from an active object. * TODO find more straightforward way to do that * * @param service a target active object * @return an active object body id */ public static UniqueID getId(Object service) { if (service instanceof StubObject && ((StubObject) service).getProxy() != null) { Proxy proxy = ((StubObject) service).getProxy(); if (proxy instanceof BodyProxy) { return ((BodyProxy) proxy).getBodyID(); } } return null; } /** * @return the subject of the client */ public Subject getSubject() { return subject; } /** * Checks that client has the specified permission. * * @return true if it has, throw {@link SecurityException} otherwise with specified error message */ public boolean checkPermission(final Permission permission, String errorMessage) { try { Subject.doAsPrivileged(subject, new PrivilegedAction<Object>() { public Object run() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(permission); } return null; } }, null); } catch (SecurityException ex) { throw new SecurityException(errorMessage, ex); } return true; } /** * Sets the history DB object associated to the current user connection. * @param history is an object to set */ public void setHistory(UserHistory history) { this.history = history; } /** * Returns the connection history object linked to the data base * @return the connection history object linked to the data base */ public UserHistory getHistory() { return history; } public void setCredentials(Credentials credentials) { this.credentials = credentials; } public Credentials getCredentials() { return credentials; } }