/* dCache - http://www.dcache.org/ * * Copyright (C) 2015 Deutsches Elektronen-Synchrotron * * This program 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, either version 3 of the * License, or (at your option) any later version. * * 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/>. */ package diskCacheV111.srm.dcache; import com.google.common.base.Throwables; import org.globus.gsi.gssapi.jaas.GlobusPrincipal; import org.springframework.dao.DataRetrievalFailureException; import javax.sql.DataSource; import java.io.ByteArrayInputStream; import java.security.cert.CertPath; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; import org.dcache.auth.LoginReply; import org.dcache.auth.LoginStrategy; import org.dcache.srm.SRMAuthorizationException; import org.dcache.srm.SRMInternalErrorException; import org.dcache.srm.SRMUser; import static diskCacheV111.srm.dcache.CanonicalizingByteArrayStore.Token; import static eu.emi.security.authn.x509.impl.OpensslNameUtils.convertFromRfc2253; import static eu.emi.security.authn.x509.proxy.ProxyUtils.getOriginalUserDN; /** * An SRM user manager that delegates authorization and user mapping to a {@code LoginStrategy} * and persists users by storing the encoded X.509 certificate chain to a database. * * Upon restoring users from the database a new login session is established by delegating * to the {@code LoginStrategy}. This does present a unique failure mode in which the login * may fail upon restore. In that case a special user instance that is flagged as not being * logged in is returned. * * Due to the repeated login, the mapped user identity may change upon restore (this may * be considered a feature). */ public final class PersistentChainUserManager extends DcacheUserManager { private static final String ENCODING = "PkiPath"; private static final String TYPE = "PkiPath"; public PersistentChainUserManager(LoginStrategy loginStrategy, DataSource dataSource) { super(loginStrategy, dataSource, TYPE); } @Override protected byte[] encode(CertPath path, LoginReply login) throws CertificateEncodingException { return path.getEncoded(ENCODING); } @Override protected SRMUser decode(String clientHost, Token token, byte[] encoded) { try { CertPath path = cf.generateCertPath(new ByteArrayInputStream(encoded), ENCODING); try { return new DcacheUser(token, login(path, clientHost)); } catch (SRMAuthorizationException e) { /* Apparently the user is no longer authorized in gPlazma. To at least allow the request * to fail gracefully, we return the least privileged user (nobody). This is not optimal * as the correct thing would be to fail all jobs of this user, but we currently have no * means to do this. * * Since we would like the admin to be able to see the DN of the owner of the request, we * add this here. */ return new DcacheUser(token, getGlobusPrincipal(path)); } } catch (CertificateException e) { throw Throwables.propagate(e); } catch (SRMInternalErrorException e) { throw new DataRetrievalFailureException("Failed to retrieve user identity", e); } } private GlobusPrincipal getGlobusPrincipal(CertPath path) { List<X509Certificate> certificates = (List<X509Certificate>) path.getCertificates(); X509Certificate[] chain = certificates.toArray(new X509Certificate[certificates.size()]); return new GlobusPrincipal(convertFromRfc2253(getOriginalUserDN(chain).getName(), true)); } }