All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sshd.server.auth.gss.UserAuthGSS Maven / Gradle / Ivy

There is a newer version: 2.14.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.sshd.server.auth.gss;

import java.util.Objects;

import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.util.NumberUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.server.auth.AbstractUserAuth;
import org.apache.sshd.server.session.ServerSession;
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.MessageProp;
import org.ietf.jgss.Oid;

/**
 * 

* Prototype user authentication handling gssapi-with-mic. Implements HandshakingUserAuth because the * process involves several steps. *

* *

* Several methods are available for overriding in specific circumstances. *

*/ public class UserAuthGSS extends AbstractUserAuth { public static final String NAME = UserAuthGSSFactory.NAME; // Oids for the Kerberos 5 mechanism and principal public static final Oid KRB5_MECH = createOID("1.2.840.113554.1.2.2"); public static final Oid KRB5_NT_PRINCIPAL = createOID("1.2.840.113554.1.2.2.1"); // The on-going GSS context. private GSSContext context; // Identity from context private String identity; public UserAuthGSS() { super(NAME); } @Override protected Boolean doAuth(Buffer buffer, boolean initial) throws Exception { ServerSession session = getServerSession(); GSSAuthenticator auth = Objects.requireNonNull(session.getGSSAuthenticator(), "No GSSAuthenticator configured"); String user = getUsername(); boolean debugEnabled = log.isDebugEnabled(); if (initial) { // Get mechanism count from buffer and look for Kerberos 5. int num = buffer.getInt(); // Protect against malicious or corrupted packets if ((num < 0) || (num > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) { log.error("doAuth({}@{}) Illogical OID entries count: {}", user, session, num); throw new IndexOutOfBoundsException("Illogical OID entries count: " + num); } boolean traceEnabled = log.isTraceEnabled(); for (int i = 1; i <= num; i++) { Oid oid = new Oid(buffer.getBytes()); if (!oid.equals(KRB5_MECH)) { if (traceEnabled) { log.trace("doAuth({}@{}) skip OID {}/{}: {}", user, session, i, num, oid); } continue; } if (debugEnabled) { log.debug("doAuth({}@{}) found Kerberos 5 after {}/{} OID(s)", user, session, i, num); } // Validate initial user before proceeding if (!auth.validateInitialUser(session, user)) { return Boolean.FALSE; } GSSManager mgr = auth.getGSSManager(); GSSCredential creds = auth.getGSSCredential(mgr); if (creds == null) { return Boolean.FALSE; } context = mgr.createContext(creds); // Send the matching mechanism back to the client byte[] out = oid.getDER(); Buffer b = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, out.length + Integer.SIZE); b.putBytes(out); session.writePacket(b); return null; } // No matching mechanism found return Boolean.FALSE; } else { int msg = buffer.getUByte(); if (!((msg == SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE) || ((msg == SshConstants.SSH_MSG_USERAUTH_GSSAPI_MIC) && context.isEstablished()))) { throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Packet not supported by user authentication method: " + SshConstants.getCommandMessageName(msg)); } if (debugEnabled) { log.debug("doAuth({}@{}) In krb5.next: msg = {}", user, session, SshConstants.getCommandMessageName(msg)); } // If the context is established, this must be a MIC message if (context.isEstablished()) { if (msg != SshConstants.SSH_MSG_USERAUTH_GSSAPI_MIC) { return Boolean.FALSE; } // Make the MIC message so the token can be verified Buffer msgbuf = new ByteArrayBuffer(); msgbuf.putBytes(ValidateUtils.checkNotNullAndNotEmpty(session.getSessionId(), "No current session ID")); msgbuf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST); msgbuf.putString(getUsername()); msgbuf.putString(getService()); msgbuf.putString(getName()); byte[] msgbytes = msgbuf.getCompactData(); byte[] inmic = buffer.getBytes(); try { context.verifyMIC(inmic, 0, inmic.length, msgbytes, 0, msgbytes.length, new MessageProp(false)); if (debugEnabled) { log.debug("doAuth({}@{}) MIC verified", getUsername(), session); } return Boolean.TRUE; } catch (GSSException e) { if (debugEnabled) { log.debug("doAuth({}@{}) GSS verification {} error: {}", user, session, e.getClass().getSimpleName(), e.getMessage()); } return Boolean.FALSE; } } else { // Not established - new token to process byte[] tok = buffer.getBytes(); byte[] out = context.acceptSecContext(tok, 0, tok.length); boolean established = context.isEstablished(); // Validate identity if context is now established if (established && (identity == null)) { GSSName srcName = context.getSrcName(); identity = srcName.toString(); if (debugEnabled) { log.debug("doAuth({}@{}) GSS identity is {}", user, session, identity); } if (!auth.validateIdentity(session, identity)) { return Boolean.FALSE; } } // Send return token if necessary if (NumberUtils.length(out) > 0) { Buffer b = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE, out.length + Integer.SIZE); b.putBytes(out); session.writePacket(b); return null; } else { return established; } } } } /** * Free any system resources used by the module. */ @Override public void destroy() { if (context != null) { try { context.dispose(); } catch (GSSException e) { if (log.isDebugEnabled()) { log.debug("Failed ({}) to dispose of context: {}", e.getClass().getSimpleName(), e.getMessage()); } } finally { context = null; } } } /** * Utility to construct an Oid from a string, ignoring the annoying exception. * * @param rep The string form * @return The Oid */ public static Oid createOID(String rep) { try { return new Oid(rep); } catch (GSSException e) { // won't happen return null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy