1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-09-09 00:59:39 +02:00

Add smack-android and redesign SASL authentication

This commit marks an important milestone with the addition of the
smack-android subproject. Smack is now able to run native on Android
without requiring any modifications, which makes the aSmack build
environment obsolete.

It was necessary to redesign the code for SASL authentication to achieve
this. Smack now comes with smack-sasl-provided for SASL implementations
that do not rely on additional APIs like javax for platforms where those
APIs are not available like Android.
This commit is contained in:
Florian Schmaus 2014-08-01 10:34:47 +02:00
parent 5a2149718a
commit 89dc3a0e85
39 changed files with 1562 additions and 675 deletions

View file

@ -0,0 +1,8 @@
description = """\
SASL with javax.security.sasl
Use javax.security.sasl for SASL."""
dependencies {
compile project(path: ':smack-core', configuration: 'sasl')
testCompile project(':smack-core').sourceSets.test.runtimeClasspath
}

View file

@ -0,0 +1,41 @@
/**
*
* Copyright the original author or authors
*
* 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.javax;
/**
* Implementation of the SASL CRAM-MD5 mechanism
*
* @author Jay Kline
*/
public class SASLCramMD5Mechanism extends SASLJavaXMechanism {
public static final String NAME = CRAMMD5;
public String getName() {
return NAME;
}
@Override
public int getPriority() {
return 300;
}
@Override
public SASLCramMD5Mechanism newInstance() {
return new SASLCramMD5Mechanism();
}
}

View file

@ -0,0 +1,41 @@
/**
*
* Copyright the original author or authors
*
* 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.javax;
/**
* Implementation of the SASL DIGEST-MD5 mechanism
*
* @author Jay Kline
*/
public class SASLDigestMD5Mechanism extends SASLJavaXMechanism {
public static final String NAME = DIGESTMD5;
public String getName() {
return NAME;
}
@Override
public int getPriority() {
return 200;
}
@Override
public SASLDigestMD5Mechanism newInstance() {
return new SASLDigestMD5Mechanism();
}
}

View file

@ -0,0 +1,63 @@
/**
*
* Copyright the original author or authors
*
* 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.javax;
/**
* Implementation of the SASL EXTERNAL mechanism.
*
* To effectively use this mechanism, Java must be configured to properly
* supply a client SSL certificate (of some sort) to the server. It is up
* to the implementer to determine how to do this. Here is one method:
*
* Create a java keystore with your SSL certificate in it:
* keytool -genkey -alias username -dname "cn=username,ou=organizationalUnit,o=organizationaName,l=locality,s=state,c=country"
*
* Next, set the System Properties:
* <ul>
* <li>javax.net.ssl.keyStore to the location of the keyStore
* <li>javax.net.ssl.keyStorePassword to the password of the keyStore
* <li>javax.net.ssl.trustStore to the location of the trustStore
* <li>javax.net.ssl.trustStorePassword to the the password of the trustStore
* </ul>
*
* Then, when the server requests or requires the client certificate, java will
* simply provide the one in the keyStore.
*
* Also worth noting is the EXTERNAL mechanism in Smack is not enabled by default.
* To enable it, the implementer will need to call SASLAuthentication.supportSASLMechamism("EXTERNAL");
*
* @author Jay Kline
*/
public class SASLExternalMechanism extends SASLJavaXMechanism {
public static final String NAME = EXTERNAL;
@Override
public String getName() {
return EXTERNAL;
}
@Override
public int getPriority() {
return 500;
}
@Override
public SASLExternalMechanism newInstance() {
return new SASLExternalMechanism();
}
}

View file

@ -0,0 +1,69 @@
/**
*
* Copyright the original author or authors
*
* 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.javax;
import java.util.Map;
import javax.security.sasl.Sasl;
/**
* Implementation of the SASL GSSAPI mechanism
*
* @author Jay Kline
*/
public class SASLGSSAPIMechanism extends SASLJavaXMechanism {
public static final String NAME = GSSAPI;
static {
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
System.setProperty("java.security.auth.login.config","gss.conf");
}
@Override
public String getName() {
return NAME;
}
@Override
protected Map<String, String> getSaslProps() {
Map<String, String> props = super.getSaslProps();
props.put(Sasl.SERVER_AUTH,"TRUE");
return props;
}
/**
* GSSAPI differs from all other SASL mechanism such that it required the FQDN host name as
* server name and not the serviceName (At least that is what old code comments of Smack tell
* us).
*/
@Override
protected String getServerName() {
return host;
}
@Override
public int getPriority() {
return 100;
}
@Override
public SASLGSSAPIMechanism newInstance() {
return new SASLGSSAPIMechanism();
}
}

View file

@ -0,0 +1,147 @@
/**
*
* Copyright © 2014 Florian Schmaus
*
* 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.javax;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
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.RealmCallback;
import javax.security.sasl.RealmChoiceCallback;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.StringUtils;
public abstract class SASLJavaXMechanism extends SASLMechanism {
protected SaslClient sc;
@Override
public abstract String getName();
@Override
protected void authenticateInternal()
throws SmackException {
String[] mechanisms = { getName() };
Map<String, String> props = getSaslProps();
try {
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", getServerName(), props,
new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
NameCallback ncb = (NameCallback) callbacks[i];
ncb.setName(authenticationId);
}
else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback pcb = (PasswordCallback) callbacks[i];
pcb.setPassword(password.toCharArray());
}
else if (callbacks[i] instanceof RealmCallback) {
RealmCallback rcb = (RealmCallback) callbacks[i];
// Retrieve the REALM from the challenge response that
// the server returned when the client initiated the
// authentication exchange. If this value is not null or
// empty, *this value* has to be sent back to the server
// in the client's response to the server's challenge
String text = rcb.getDefaultText();
// The SASL client (sc) created in smack uses
// rcb.getText when creating the negotiatedRealm to send
// it back to the server. Make sure that this value
// matches the server's realm
rcb.setText(text);
}
else if (callbacks[i] instanceof RealmChoiceCallback) {
// unused, prevents UnsupportedCallbackException
// RealmChoiceCallback rccb =
// (RealmChoiceCallback)callbacks[i];
}
else {
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
});
}
catch (SaslException e) {
throw new SmackException(e);
}
}
@Override
protected void authenticateInternal(CallbackHandler cbh)
throws SmackException {
String[] mechanisms = { getName() };
Map<String, String> props = getSaslProps();
try {
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);
}
catch (SaslException e) {
throw new SmackException(e);
}
}
protected String getAuthenticationText() throws SmackException {
String authenticationText = null;
if (sc.hasInitialResponse()) {
byte[] response;
try {
response = sc.evaluateChallenge(new byte[0]);
}
catch (SaslException e) {
throw new SmackException(e);
}
authenticationText = StringUtils.encodeBase64(response, false);
}
return authenticationText;
}
@Override
protected byte[] evaluateChallenge(byte[] challenge) throws SmackException {
try {
if (challenge != null) {
return sc.evaluateChallenge(challenge);
}
else {
return sc.evaluateChallenge(new byte[0]);
}
}
catch (SaslException e) {
throw new SmackException(e);
}
}
protected Map<String,String> getSaslProps() {
return new HashMap<String, String>();
}
protected String getServerName() {
return serviceName;
}
}

View file

@ -0,0 +1,42 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* 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.javax;
import java.util.List;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.initializer.SmackAndOsgiInitializer;
public class SASLJavaXSmackInitializer extends SmackAndOsgiInitializer {
@Override
public List<Exception> initialize() {
SASLAuthentication.registerSASLMechanism(new SASLExternalMechanism());
SASLAuthentication.registerSASLMechanism(new SASLGSSAPIMechanism());
SASLAuthentication.registerSASLMechanism(new SASLDigestMD5Mechanism());
SASLAuthentication.registerSASLMechanism(new SASLCramMD5Mechanism());
SASLAuthentication.registerSASLMechanism(new SASLPlainMechanism());
return null;
}
@Override
public List<Exception> initialize(ClassLoader classLoader) {
return initialize();
}
}

View file

@ -0,0 +1,41 @@
/**
*
* Copyright the original author or authors
*
* 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.javax;
/**
* Implementation of the SASL PLAIN mechanism
*
* @author Jay Kline
*/
public class SASLPlainMechanism extends SASLJavaXMechanism {
public static final String NAME = PLAIN;
public String getName() {
return NAME;
}
@Override
public int getPriority() {
return 400;
}
@Override
public SASLPlainMechanism newInstance() {
return new SASLPlainMechanism();
}
}

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.2.0"
enabled="true" immediate="true" name="Smack Resolver JavaX API">
<implementation
class="org.jivesoftware.smack.sasl.javax.SASLJavaXSmackInitializer" />
</scr:component>

View file

@ -0,0 +1,34 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* 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.javax;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.sasl.DigestMd5SaslTest;
import org.junit.Test;
public class SASLDigestMD5Test extends DigestMd5SaslTest {
public SASLDigestMD5Test() {
super(new SASLDigestMD5Mechanism());
}
@Test
public void testDigestMD5() throws NotConnectedException, SmackException {
runTest();
}
}