/* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.security.sasl.ntlm; import com.sun.security.ntlm.NTLMException;import com.sun.security.ntlm.Server;import java.io.IOException;import java.security.GeneralSecurityException;import java.util.Map;import java.util.Random;import javax.security.auth.callback.Callback;import javax.security.auth.callback.CallbackHandler;import javax.security.auth.callback.NameCallback;import javax.security.auth.callback.PasswordCallback;import javax.security.auth.callback.UnsupportedCallbackException;import javax.security.sasl.*; /** * Required callbacks: * - RealmCallback * used as key by handler to fetch password, optional * - NameCallback * used as key by handler to fetch password * - PasswordCallback * handler must enter password for username/realm supplied * * Environment properties that affect the implementation: * * javax.security.sasl.qop * String, quality of protection; only "auth" is accepted, default "auth" * * com.sun.security.sasl.ntlm.version * String, name a specific version to accept: * LM/NTLM: Original NTLM v1 * LM: Original NTLM v1, LM only * NTLM: Original NTLM v1, NTLM only * NTLM2: NTLM v1 with Client Challenge * LMv2/NTLMv2: NTLM v2 * LMv2: NTLM v2, LM only * NTLMv2: NTLM v2, NTLM only * If not specified, use system property "ntlm.version". If also * not specfied, all versions are accepted. * * com.sun.security.sasl.ntlm.domain * String, the domain of the server, default is server name (fqdn parameter) * * com.sun.security.sasl.ntlm.random * java.util.Random, the nonce source. Default null, an internal * java.util.Random object will be used * * Negotiated Properties: * * javax.security.sasl.qop * Always "auth" * * com.sun.security.sasl.ntlm.hostname * The hostname for the user, provided by the client * */ final class NTLMServer implements SaslServer { private final static String NTLM_VERSION = "com.sun.security.sasl.ntlm.version"; private final static String NTLM_DOMAIN = "com.sun.security.sasl.ntlm.domain"; private final static String NTLM_HOSTNAME = "com.sun.security.sasl.ntlm.hostname"; private static final String NTLM_RANDOM = "com.sun.security.sasl.ntlm.random"; private final Random random; private final Server server; private byte[] nonce; private int step = 0; private String authzId; private final String mech; private String hostname; /** * @param mech not null * @param protocol not null for Sasl, ignored in NTLM * @param serverName not null for Sasl, can be null in NTLM. If non-null, * might be used as domain if not provided in props * @param props can be null * @param cbh can be null for Sasl, but will throw NPE in auth for NTLM * @throws SaslException */ NTLMServer(String mech, String protocol, String serverName, Map props, final CallbackHandler cbh) throws SaslException { this.mech = mech; String version = null; String domain = null; Random rtmp = null; if (props != null) { domain = (String) props.get(NTLM_DOMAIN); version = (String)props.get(NTLM_VERSION); rtmp = (Random)props.get(NTLM_RANDOM); } random = rtmp != null ? rtmp : new Random(); if (version == null) { version = System.getProperty("ntlm.version"); } if (domain == null) { domain = serverName; } if (domain == null) { throw new NullPointerException("Domain must be provided as" + " the serverName argument or in props"); } try { server = new Server(version, domain) { public char[] getPassword(String ntdomain, String username) { try { RealmCallback rcb = new RealmCallback( "Domain: ", ntdomain); NameCallback ncb = new NameCallback( "Name: ", username); PasswordCallback pcb = new PasswordCallback( "Password: ", false); cbh.handle(new Callback[] { rcb, ncb, pcb }); char[] passwd = pcb.getPassword(); pcb.clearPassword(); return passwd; } catch (IOException ioe) { return null; } catch (UnsupportedCallbackException uce) { return null; } } }; } catch (NTLMException ne) { throw new SaslException( "NTLM: Invalid version string: " + version, ne); } nonce = new byte[8]; } @Override public String getMechanismName() { return mech; } @Override public byte[] evaluateResponse(byte[] response) throws SaslException { try { step++; if (step == 1) { random.nextBytes(nonce); return server.type2(response, nonce); } else { String[] out = server.verify(response, nonce); authzId = out[0]; hostname = out[1]; return null; } } catch (GeneralSecurityException ex) { throw new SaslException("", ex); } } @Override public boolean isComplete() { return step >= 2; } @Override public String getAuthorizationID() { return authzId; } @Override public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException { throw new UnsupportedOperationException("Not supported yet."); } @Override public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException { throw new UnsupportedOperationException("Not supported yet."); } @Override public Object getNegotiatedProperty(String propName) { if (propName.equals(Sasl.QOP)) { return "auth"; } else if (propName.equals(NTLM_HOSTNAME)) { return hostname; } else { return null; } } @Override public void dispose() throws SaslException { return; }}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.security.sasl.ntlm;
import com.sun.security.ntlm.NTLMException;
import com.sun.security.ntlm.Server;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.Random;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.*;
/**
* Required callbacks:
* - RealmCallback
* used as key by handler to fetch password, optional
* - NameCallback
* used as key by handler to fetch password
* - PasswordCallback
* handler must enter password for username/realm supplied
*
* Environment properties that affect the implementation:
*
* javax.security.sasl.qop
* String, quality of protection; only "auth" is accepted, default "auth"
*
* com.sun.security.sasl.ntlm.version
* String, name a specific version to accept:
* LM/NTLM: Original NTLM v1
* LM: Original NTLM v1, LM only
* NTLM: Original NTLM v1, NTLM only
* NTLM2: NTLM v1 with Client Challenge
* LMv2/NTLMv2: NTLM v2
* LMv2: NTLM v2, LM only
* NTLMv2: NTLM v2, NTLM only
* If not specified, use system property "ntlm.version". If also
* not specfied, all versions are accepted.
*
* com.sun.security.sasl.ntlm.domain
* String, the domain of the server, default is server name (fqdn parameter)
*
* com.sun.security.sasl.ntlm.random
* java.util.Random, the nonce source. Default null, an internal
* java.util.Random object will be used
*
* Negotiated Properties:
*
* javax.security.sasl.qop
* Always "auth"
*
* com.sun.security.sasl.ntlm.hostname
* The hostname for the user, provided by the client
*
*/
final class NTLMServer implements SaslServer {
private final static String NTLM_VERSION =
"com.sun.security.sasl.ntlm.version";
private final static String NTLM_DOMAIN =
"com.sun.security.sasl.ntlm.domain";
private final static String NTLM_HOSTNAME =
"com.sun.security.sasl.ntlm.hostname";
private static final String NTLM_RANDOM =
"com.sun.security.sasl.ntlm.random";
private final Random random;
private final Server server;
private byte[] nonce;
private int step = 0;
private String authzId;
private final String mech;
private String hostname;
/**
* @param mech not null
* @param protocol not null for Sasl, ignored in NTLM
* @param serverName not null for Sasl, can be null in NTLM. If non-null,
* might be used as domain if not provided in props
* @param props can be null
* @param cbh can be null for Sasl, but will throw NPE in auth for NTLM
* @throws SaslException
*/
NTLMServer(String mech, String protocol, String serverName,
Map props, final CallbackHandler cbh) throws SaslException {
this.mech = mech;
String version = null;
String domain = null;
Random rtmp = null;
if (props != null) {
domain = (String) props.get(NTLM_DOMAIN);
version = (String)props.get(NTLM_VERSION);
rtmp = (Random)props.get(NTLM_RANDOM);
}
random = rtmp != null ? rtmp : new Random();
if (version == null) {
version = System.getProperty("ntlm.version");
}
if (domain == null) {
domain = serverName;
}
if (domain == null) {
throw new NullPointerException("Domain must be provided as"
+ " the serverName argument or in props");
}
try {
server = new Server(version, domain) {
public char[] getPassword(String ntdomain, String username) {
try {
RealmCallback rcb = new RealmCallback(
"Domain: ", ntdomain);
NameCallback ncb = new NameCallback(
"Name: ", username);
PasswordCallback pcb = new PasswordCallback(
"Password: ", false);
cbh.handle(new Callback[] { rcb, ncb, pcb });
char[] passwd = pcb.getPassword();
pcb.clearPassword();
return passwd;
} catch (IOException ioe) {
return null;
} catch (UnsupportedCallbackException uce) {
return null;
}
}
};
} catch (NTLMException ne) {
throw new SaslException(
"NTLM: Invalid version string: " + version, ne);
}
nonce = new byte[8];
}
@Override
public String getMechanismName() {
return mech;
}
@Override
public byte[] evaluateResponse(byte[] response) throws SaslException {
try {
step++;
if (step == 1) {
random.nextBytes(nonce);
return server.type2(response, nonce);
} else {
String[] out = server.verify(response, nonce);
authzId = out[0];
hostname = out[1];
return null;
}
} catch (GeneralSecurityException ex) {
throw new SaslException("", ex);
}
}
@Override
public boolean isComplete() {
return step >= 2;
}
@Override
public String getAuthorizationID() {
return authzId;
}
@Override
public byte[] unwrap(byte[] incoming, int offset, int len)
throws SaslException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public byte[] wrap(byte[] outgoing, int offset, int len)
throws SaslException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Object getNegotiatedProperty(String propName) {
if (propName.equals(Sasl.QOP)) {
return "auth";
} else if (propName.equals(NTLM_HOSTNAME)) {
return hostname;
} else {
return null;
}
}
@Override
public void dispose() throws SaslException {
return;
}
}