📄 saslauthentication.java
字号:
}
catch (SaslException e) {
Log.debug("SaslException", e);
authenticationFailed(session);
status = Status.failed;
}
}
else {
Log.fatal("SaslServer is null, should be valid object instead.");
authenticationFailed(session);
status = Status.failed;
}
}
else {
Log.warn(
"Client responded to a MECH we don't support: '" + mechanism + "'");
authenticationFailed(session);
status = Status.failed;
}
break;
default:
authenticationFailed(session);
status = Status.failed;
// Ignore
break;
}
}
else {
Log.debug("Unknown namespace sent in auth element: " + doc.asXML());
authenticationFailed(session);
status = Status.failed;
}
// Check if SASL authentication has finished so we can clean up temp information
if (status == Status.failed || status == Status.authenticated) {
// Remove the SaslServer from the Session
session.removeSessionData("SaslServer");
// Remove the requested SASL mechanism by the client
session.removeSessionData("SaslMechanism");
}
return status;
}
private static Status doAnonymousAuthentication(Session session) {
if (XMPPServer.getInstance().getIQAuthHandler().isAnonymousAllowed()) {
// Just accept the authentication :)
authenticationSuccessful(session, null, null);
return Status.authenticated;
}
else {
// anonymous login is disabled so close the connection
authenticationFailed(session);
return Status.failed;
}
}
private static Status doPlainAuthentication(Session session, Element doc)
throws UnsupportedEncodingException {
String username;
String password;
String response = doc.getTextTrim();
if (response == null || response.length() == 0) {
// No info was provided so send a challenge to get it
sendChallenge(session, new byte[0]);
return Status.needResponse;
}
// Parse data and obtain username & password
String data = new String(StringUtils.decodeBase64(response), CHARSET);
StringTokenizer tokens = new StringTokenizer(data, "\0");
if (tokens.countTokens() > 2) {
// Skip the "authorization identity"
tokens.nextToken();
}
username = tokens.nextToken();
password = tokens.nextToken();
try {
AuthToken token = AuthFactory.authenticate(username, password);
authenticationSuccessful(session, token.getUsername(), null);
return Status.authenticated;
}
catch (UnauthorizedException e) {
authenticationFailed(session);
return Status.failed;
}
}
private static Status doExternalAuthentication(Session session, Element doc)
throws UnsupportedEncodingException {
// Only accept EXTERNAL SASL for s2s. At this point the connection has already
// been secured using TLS
if (!(session instanceof IncomingServerSession)) {
return Status.failed;
}
String hostname = doc.getTextTrim();
if (hostname == null || hostname.length() == 0) {
// No hostname was provided so send a challenge to get it
sendChallenge(session, new byte[0]);
return Status.needResponse;
}
hostname = new String(StringUtils.decodeBase64(hostname), CHARSET);
// Check if cerificate validation is disabled for s2s
// Flag that indicates if certificates of the remote server should be validated.
// Disabling certificate validation is not recommended for production environments.
boolean verify =
JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify", true);
if (!verify) {
authenticationSuccessful(session, hostname, null);
return Status.authenticated;
}
// Check that hostname matches the one provided in a certificate
SocketConnection connection = (SocketConnection) session.getConnection();
try {
for (Certificate certificate : connection.getSSLSession().getPeerCertificates()) {
if (TLSStreamHandler.getPeerIdentities((X509Certificate) certificate)
.contains(hostname)) {
authenticationSuccessful(session, hostname, null);
return Status.authenticated;
}
}
}
catch (SSLPeerUnverifiedException e) {
Log.warn("Error retrieving client certificates of: " + session, e);
}
authenticationFailed(session);
return Status.failed;
}
private static void sendChallenge(Session session, byte[] challenge) {
StringBuilder reply = new StringBuilder(250);
if(challenge == null) {
challenge = new byte[0];
}
String challenge_b64 = StringUtils.encodeBase64(challenge).trim();
if ("".equals(challenge_b64)) {
challenge_b64 = "="; // Must be padded if null
}
reply.append(
"<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
reply.append(challenge_b64);
reply.append("</challenge>");
session.getConnection().deliverRawText(reply.toString());
}
private static void authenticationSuccessful(Session session, String username,
byte[] successData) {
StringBuilder reply = new StringBuilder(80);
reply.append("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"");
if (successData != null) {
String successData_b64 = StringUtils.encodeBase64(successData).trim();
reply.append(">").append(successData_b64).append("</success>");
}
else {
reply.append("/>");
}
session.getConnection().deliverRawText(reply.toString());
// We only support SASL for c2s
if (session instanceof ClientSession) {
((ClientSession) session).setAuthToken(new AuthToken(username));
}
else if (session instanceof IncomingServerSession) {
String hostname = username;
// Set the first validated domain as the address of the session
session.setAddress(new JID(null, hostname, null));
// Add the validated domain as a valid domain. The remote server can
// now send packets from this address
((IncomingServerSession) session).addValidatedDomain(hostname);
}
}
private static void authenticationFailed(Session session) {
StringBuilder reply = new StringBuilder(80);
reply.append("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
reply.append("<not-authorized/></failure>");
session.getConnection().deliverRawText(reply.toString());
// Give a number of retries before closing the connection
Integer retries = (Integer) session.getSessionData("authRetries");
if (retries == null) {
retries = 1;
}
else {
retries = retries + 1;
}
session.setSessionData("authRetries", retries);
if (retries >= JiveGlobals.getIntProperty("xmpp.auth.retries", 3) ) {
// Close the connection
session.getConnection().close();
}
}
/**
* Adds a new SASL mechanism to the list of supported SASL mechanisms by the server. The
* new mechanism will be offered to clients and connection managers as stream features.
*
* @param mechanism the new SASL mechanism.
*/
public static void addSupportedMechanism(String mechanism) {
mechanisms.add(mechanism);
}
/**
* Removes a SASL mechanism from the list of supported SASL mechanisms by the server.
*
* @param mechanism the SASL mechanism to remove.
*/
public static void removeSupportedMechanism(String mechanism) {
mechanisms.remove(mechanism);
}
/**
* Returns the list of supported SASL mechanisms by the server. Note that Java may have
* support for more mechanisms but some of them may not be returned since a special setup
* is required that might be missing. Use {@link #addSupportedMechanism(String)} to add
* new SASL mechanisms.
*
* @return the list of supported SASL mechanisms by the server.
*/
public static Set<String> getSupportedMechanisms() {
return Collections.unmodifiableSet(mechanisms);
}
private static void initMechanisms() {
mechanisms = new HashSet<String>();
String available = JiveGlobals.getXMLProperty("sasl.mechs");
if (available == null) {
mechanisms.add("ANONYMOUS");
mechanisms.add("PLAIN");
mechanisms.add("DIGEST-MD5");
mechanisms.add("CRAM-MD5");
} else {
StringTokenizer st = new StringTokenizer(available, " ,\t\n\r\f");
while (st.hasMoreTokens()) {
String mech = st.nextToken().toUpperCase();
// Check that the mech is a supported mechansim. Maybe we shouldnt check this and allow any?
if (mech.equals("ANONYMOUS") ||
mech.equals("PLAIN") ||
mech.equals("DIGEST-MD5") ||
mech.equals("CRAM-MD5") ||
mech.equals("GSSAPI")) {
Log.debug("SASLAuthentication: Added " + mech + " to mech list");
mechanisms.add(mech);
}
}
if (mechanisms.contains("GSSAPI")) {
if (JiveGlobals.getXMLProperty("sasl.gssapi.config") != null) {
System.setProperty("java.security.krb5.debug",
JiveGlobals.getXMLProperty("sasl.gssapi.debug", "false"));
System.setProperty("java.security.auth.login.config",
JiveGlobals.getXMLProperty("sasl.gssapi.config"));
System.setProperty("javax.security.auth.useSubjectCredsOnly",
JiveGlobals.getXMLProperty("sasl.gssapi.useSubjectCredsOnly", "false"));
} else {
//Not configured, remove the option.
Log.debug("SASLAuthentication: Removed GSSAPI from mech list");
mechanisms.remove("GSSAPI");
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -