/* 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 org.dcache.dss; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Supplier; import org.ietf.jgss.ChannelBinding; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSManager; import org.ietf.jgss.GSSName; import org.ietf.jgss.Oid; import java.io.IOException; import java.net.InetSocketAddress; import org.dcache.util.Args; public class KerberosDssContextFactory implements DssContextFactory { private final Function<GSSName, GSSContext> createInitialContext = new Function<GSSName, GSSContext>() { @Override public GSSContext apply(GSSName name) { try { return manager.createContext(name, krb5Mechanism, credential, GSSContext.DEFAULT_LIFETIME); } catch (GSSException e) { throw new WrappedGssException(e); } } }; private final Supplier<GSSContext> createAcceptingContext = new Supplier<GSSContext>() { @Override public GSSContext get() { try { return manager.createContext(credential); } catch (GSSException e) { throw new WrappedGssException(e); } } }; private final Oid krb5Mechanism; private final GSSManager manager; private final GSSCredential credential; private final Optional<GSSName> peer; protected KerberosDssContextFactory(String principal, Optional<String> peerName) throws GSSException { try { krb5Mechanism = new Oid("1.2.840.113554.1.2.2"); manager = GSSManager.getInstance(); credential = manager.createCredential(createName(principal), GSSCredential.DEFAULT_LIFETIME, krb5Mechanism, GSSCredential.ACCEPT_ONLY); peer = peerName.transform(new Function<String, GSSName>() { @Override public GSSName apply(String name) { return KerberosDssContextFactory.this.createName(name); } }); } catch (WrappedGssException e) { throw e.getCause(); } } public KerberosDssContextFactory(String args) throws GSSException { this(new Args(args)); } public KerberosDssContextFactory(Args args) throws GSSException { this(args.argv(0), Optional.<String>absent()); } public KerberosDssContextFactory(String principal, String peerName) throws GSSException { this(principal, Optional.of(peerName)); } @Override public DssContext create(InetSocketAddress remoteSocketAddress, InetSocketAddress localSocketAddress) throws IOException { try { GSSContext context = peer.transform(createInitialContext).or(createAcceptingContext); ChannelBinding cb = new ChannelBinding(remoteSocketAddress.getAddress(), localSocketAddress.getAddress(), null); context.setChannelBinding(cb); return new KerberosDssContext(context); } catch (WrappedGssException e) { throw new IOException(e.getCause()); } catch (GSSException e) { throw new IOException(e); } } private GSSName createName(String name) { try { return manager.createName(name, null); } catch (GSSException e) { throw new WrappedGssException(e); } } private static class WrappedGssException extends RuntimeException { private static final long serialVersionUID = -4196646840625155999L; public WrappedGssException(GSSException e) { super(e); } @Override public synchronized GSSException getCause() { return (GSSException) super.getCause(); } } }