diff --git a/source/org/jivesoftware/smack/SASLAuthentication.java b/source/org/jivesoftware/smack/SASLAuthentication.java index 81a0fbf81..2f6304ae4 100644 --- a/source/org/jivesoftware/smack/SASLAuthentication.java +++ b/source/org/jivesoftware/smack/SASLAuthentication.java @@ -27,6 +27,7 @@ import org.jivesoftware.smack.packet.Session; import org.jivesoftware.smack.sasl.SASLAnonymous; import org.jivesoftware.smack.sasl.SASLMechanism; import org.jivesoftware.smack.sasl.SASLPlainMechanism; +import org.jivesoftware.smack.sasl.SASLGSSAPIMechanism; import java.io.IOException; import java.lang.reflect.Constructor; @@ -79,7 +80,8 @@ public class SASLAuthentication implements UserAuthentication { static { // Register SASL mechanisms supported by Smack - registerSASLMechanism(0, "PLAIN", SASLPlainMechanism.class); + registerSASLMechanism(0, "GSSAPI", SASLGSSAPIMechanism.class); + registerSASLMechanism(1, "PLAIN", SASLPlainMechanism.class); } /** diff --git a/source/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java b/source/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java new file mode 100644 index 000000000..5b71314c6 --- /dev/null +++ b/source/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java @@ -0,0 +1,258 @@ +/** + * $RCSfile$ + * $Revision: $ + * $Date: $ + * + * + * All rights reserved. Licensed 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.jivesoftware.smack.sasl; + +import javax.security.sasl.*; +import java.util.*; +import java.io.IOException; + +import org.jivesoftware.smack.SASLAuthentication; +import org.jivesoftware.smack.util.Base64; + +/** + * Implementation of the SASL GSSAPI mechanisn + * + * + * @author Jay Kline + */ +public class SASLGSSAPIMechanism extends SASLMechanism { + + private static final String protocol = "xmpp"; + private static final String[] mechanisms = {"GSSAPI"}; + private SaslClient sc; + + public SASLGSSAPIMechanism(SASLAuthentication saslAuthentication) { + super(saslAuthentication); + + System.setProperty("java.security.krb5.debug","true"); + System.setProperty("javax.security.auth.useSubjectCredsOnly","false"); + System.setProperty("java.security.auth.login.config","gss.conf"); + + } + + protected String getName() { + return "GSSAPI"; + } + + /** + * Builds and sends the auth stanza to the server. + * This overrides from the abstract class because the initial token + * needed for GSSAPI is binary, and not safe to put in a string, thus + * getAuthenticationText() cannot be used. + * + * @param username the username of the user being authenticated. + * @param host the hostname where the user account resides. + * @param password the password of the user (ignored for GSSAPI) + * @throws IOException If a network error occures while authenticating. + */ + public void authenticate(String username, String host, String password) throws IOException { + // Build the authentication stanza encoding the authentication text + StringBuffer stanza = new StringBuffer(); + Map props = new HashMap(); + + sc = Sasl.createSaslClient(mechanisms, username, protocol, host, props, null); + + stanza.append(""); + if(sc.hasInitialResponse()) { + byte[] response = sc.evaluateChallenge(new byte[0]); + String authenticationText = Base64.encodeBytes(response,Base64.DONT_BREAK_LINES); + if(authenticationText != null && !authenticationText.equals("")) { + stanza.append(authenticationText); + } + } + stanza.append(""); + + // Send the authentication to the server + getSASLAuthentication().send(stanza.toString()); + } + + + protected String getAuthenticationText(String username, String host, String password) { + // Unused, see authenticate + return null; + } + + /** + * The server is challenging the SASL mechanism for the stanza he just sent. Send a + * response to the server's challenge. This overrieds from the abstract class because the + * tokens needed for GSSAPI are binary, and not safe to put in a string, thus + * getChallengeResponse() cannot be used. + * + * @param challenge a base64 encoded string representing the challenge. + */ + public void challengeReceived(String challenge) throws IOException { + // Build the challenge response stanza encoding the response text + StringBuffer stanza = new StringBuffer(); + + byte response[]; + if(challenge != null) { + response = sc.evaluateChallenge(Base64.decode(challenge)); + } else { + response = sc.evaluateChallenge(null); + } + + String authenticationText = Base64.encodeBytes(response,Base64.DONT_BREAK_LINES); + if(authenticationText.equals("")) { + authenticationText = "="; + } + + stanza.append(""); + stanza.append(authenticationText); + stanza.append(""); + + // Send the authentication to the server + getSASLAuthentication().send(stanza.toString()); + } + + protected String getChallengeResponse(byte[] bytes) { + // Unused, see challengeReceived + return null; + } +} +/** + * $RCSfile$ + * $Revision: $ + * $Date: $ + * + * + * All rights reserved. Licensed 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.jivesoftware.smack.sasl; + +import javax.security.sasl.*; +import java.util.*; +import java.io.IOException; + +import org.jivesoftware.smack.SASLAuthentication; +import org.jivesoftware.smack.util.Base64; + +/** + * Implementation of the SASL GSSAPI mechanisn + * + * + * @author Jay Kline + */ +public class SASLGSSAPIMechanism extends SASLMechanism { + + private static final String protocol = "xmpp"; + private static final String[] mechanisms = {"GSSAPI"}; + private SaslClient sc; + + public SASLGSSAPIMechanism(SASLAuthentication saslAuthentication) { + super(saslAuthentication); + + System.setProperty("java.security.krb5.debug","true"); + System.setProperty("javax.security.auth.useSubjectCredsOnly","false"); + System.setProperty("java.security.auth.login.config","gss.conf"); + + } + + protected String getName() { + return "GSSAPI"; + } + + /** + * Builds and sends the auth stanza to the server. + * This overrides from the abstract class because the initial token + * needed for GSSAPI is binary, and not safe to put in a string, thus + * getAuthenticationText() cannot be used. + * + * @param username the username of the user being authenticated. + * @param host the hostname where the user account resides. + * @param password the password of the user (ignored for GSSAPI) + * @throws IOException If a network error occures while authenticating. + */ + public void authenticate(String username, String host, String password) throws IOException { + // Build the authentication stanza encoding the authentication text + StringBuffer stanza = new StringBuffer(); + Map props = new HashMap(); + + sc = Sasl.createSaslClient(mechanisms, username, protocol, host, props, null); + + stanza.append(""); + if(sc.hasInitialResponse()) { + byte[] response = sc.evaluateChallenge(new byte[0]); + String authenticationText = Base64.encodeBytes(response,Base64.DONT_BREAK_LINES); + if(authenticationText != null && !authenticationText.equals("")) { + stanza.append(authenticationText); + } + } + stanza.append(""); + + // Send the authentication to the server + getSASLAuthentication().send(stanza.toString()); + } + + + protected String getAuthenticationText(String username, String host, String password) { + // Unused, see authenticate + return null; + } + + /** + * The server is challenging the SASL mechanism for the stanza he just sent. Send a + * response to the server's challenge. This overrieds from the abstract class because the + * tokens needed for GSSAPI are binary, and not safe to put in a string, thus + * getChallengeResponse() cannot be used. + * + * @param challenge a base64 encoded string representing the challenge. + */ + public void challengeReceived(String challenge) throws IOException { + // Build the challenge response stanza encoding the response text + StringBuffer stanza = new StringBuffer(); + + byte response[]; + if(challenge != null) { + response = sc.evaluateChallenge(Base64.decode(challenge)); + } else { + response = sc.evaluateChallenge(null); + } + + String authenticationText = Base64.encodeBytes(response,Base64.DONT_BREAK_LINES); + if(authenticationText.equals("")) { + authenticationText = "="; + } + + stanza.append(""); + stanza.append(authenticationText); + stanza.append(""); + + // Send the authentication to the server + getSASLAuthentication().send(stanza.toString()); + } + + protected String getChallengeResponse(byte[] bytes) { + // Unused, see challengeReceived + return null; + } +} diff --git a/source/org/jivesoftware/smack/util/Base64.java b/source/org/jivesoftware/smack/util/Base64.java index 3f02739eb..613542ca3 100644 --- a/source/org/jivesoftware/smack/util/Base64.java +++ b/source/org/jivesoftware/smack/util/Base64.java @@ -44,7 +44,7 @@ package org.jivesoftware.smack.util; * @author rob@iharder.net * @version 2.1 */ -class Base64 { +public class Base64 { /* ******** P U B L I C F I E L D S ******** */ @@ -1442,3 +1442,4 @@ class Base64 { } // end class Base64 +