diff --git a/source/org/jivesoftware/smack/sasl/SASLMechanism.java b/source/org/jivesoftware/smack/sasl/SASLMechanism.java new file mode 100644 index 000000000..d42375f4e --- /dev/null +++ b/source/org/jivesoftware/smack/sasl/SASLMechanism.java @@ -0,0 +1,120 @@ +/** + * $RCSfile$ + * $Revision: $ + * $Date: $ + * + * Copyright 2003-2004 Jive Software. + * + * 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 org.jivesoftware.smack.SASLAuthentication; +import org.jivesoftware.smack.util.StringUtils; + +import java.io.IOException; + +/** + * Base class for SASL mechanisms. Subclasses must implement three methods: + * + * + * @author Gaston Dombiak + */ +public abstract class SASLMechanism { + + private SASLAuthentication saslAuthentication; + + public SASLMechanism(SASLAuthentication saslAuthentication) { + super(); + this.saslAuthentication = saslAuthentication; + } + + /** + * Builds and sends the auth stanza to the server. + * + * @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. + * @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(); + stanza.append(""); + String authenticationText = getAuthenticationText(username, host, password); + if (authenticationText != null) { + stanza.append(StringUtils.encodeBase64(authenticationText)); + } + stanza.append(""); + + // Send the authentication to the server + getSASLAuthentication().send(stanza.toString()); + } + + /** + * The server is challenging the SASL mechanism for the stanza he just sent. Send a + * response to the server's challenge. + * + * @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(); + stanza.append(""); + String authenticationText = getChallengeResponse(StringUtils.decodeBase64(challenge)); + stanza.append(StringUtils.encodeBase64(authenticationText)); + stanza.append(""); + + // Send the authentication to the server + getSASLAuthentication().send(stanza.toString()); + } + + /** + * Returns the response text to send answering the challenge sent by the server. Mechanisms + * that will never receive a challenge may redefine this method returning null. + * + * @param bytes the challenge sent by the server. + * @return the response text to send to answer the challenge sent by the server. + */ + protected abstract String getChallengeResponse(byte[] bytes); + + /** + * Returns the common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4. + * + * @return the common name of the SASL mechanism. + */ + protected abstract String getName(); + + /** + * Returns the authentication text to include in the initial auth stanza + * or null if nothing should be added. + * + * @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. + * @return the authentication text to include in the initial auth stanza + * or null if nothing should be added. + */ + protected abstract String getAuthenticationText(String username, String host, String password); + + protected SASLAuthentication getSASLAuthentication() { + return saslAuthentication; + } +} diff --git a/source/org/jivesoftware/smack/sasl/SASLPlainMechanism.java b/source/org/jivesoftware/smack/sasl/SASLPlainMechanism.java new file mode 100644 index 000000000..7c534216d --- /dev/null +++ b/source/org/jivesoftware/smack/sasl/SASLPlainMechanism.java @@ -0,0 +1,58 @@ +/** + * $RCSfile$ + * $Revision: $ + * $Date: $ + * + * Copyright 2003-2004 Jive Software. + * + * 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 org.jivesoftware.smack.SASLAuthentication; + +/** + * Implementation of the SASL PLAIN mechanisn as defined by the + * IETF draft + * document. + * + * @author Gaston Dombiak + */ +public class SASLPlainMechanism extends SASLMechanism { + + public SASLPlainMechanism(SASLAuthentication saslAuthentication) { + super(saslAuthentication); + } + + protected String getName() { + return "PLAIN"; + } + + protected String getAuthenticationText(String username, String host, String password) { + // Build the text containing the "authorization identity" + NUL char + + // "authentication identity" + NUL char + "clear-text password" + StringBuffer text = new StringBuffer(); + text.append(username).append("@").append(host); + text.append('\0'); + text.append(username); + text.append('\0'); + text.append(password); + return text.toString(); + } + + protected String getChallengeResponse(byte[] bytes) { + // Return null since this mechanism will never get a challenge from the server + return null; + } +}