mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-09-09 10:19:41 +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:
parent
5a2149718a
commit
89dc3a0e85
39 changed files with 1562 additions and 675 deletions
8
smack-sasl-javax/build.gradle
Normal file
8
smack-sasl-javax/build.gradle
Normal 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
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue