我正在开发一对一的聊天,但我面临服务器所需的SSL / TLS问题但在客户端禁用,不知道我做错了什么,请帮我弄清楚错误
我的服务类:
class ChatService:Service() {
var text = ""
var chat:Chat?=null
companion object {
private val DOMAIN = "localhost"
private val USERNAME = "admin@localhost"
private val PASSWORD = "localhost"
var cm: ConnectivityManager? = null
var xmpp: MyXMPP? = null
var ServerchatCreated = false
fun isNetworkConnected(): Boolean {
return cm!!.getActiveNetworkInfo() != null
}
}
override fun onCreate() {
super.onCreate()
cm= getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
xmpp = MyXMPP.getInstance(this, DOMAIN, USERNAME, PASSWORD);
xmpp!!.connect("onCreate");
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return LocalBinder<ChatService>(this)
}
override fun onDestroy() {
super.onDestroy()
xmpp!!.disconnect();
}
}
我的XMPP类用于连接:
companion object {
fun getInstance(context: ChatService, server: String, user: String, pass: String): MyXMPP {
if (instance == null) {
instance = MyXMPP(context, server, user, pass)
instanceCreated = true
}
return instance!!
}
}
constructor(context: ChatService, serverAdress: String, logiUser: String, passwordser: String) {
this.serverAddress = serverAdress
this.loginUser = logiUser
this.passwordUser = passwordser
this.context = context
initialiseConnection()
}
private fun initialiseConnection() {
val serviceName = JidCreate.domainBareFrom("localhost")
val config = XMPPTCPConnectionConfiguration.builder()
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
config.setServiceName(serviceName)
config.setHostAddress(InetAddress.getByName("192.168.0.101"))//my ip address
config.setPort(5222)
config.setXmppDomain(serviceName)
config.setDebuggerEnabled(true)
//System.setProperty("smack.debugEnabled", "true")
XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true)
XMPPTCPConnection.setUseStreamManagementDefault(true)
connection = XMPPTCPConnection(config.build())
val connectionListener = XMPPConnectionListener()
connection!!.addConnectionListener(connectionListener)
}
内部类到MyXMPP类:
inner class XMPPConnectionListener : ConnectionListener {
override fun connected(connection: XMPPConnection) {
Log.d("xmpp", "Connected!")
connected = true
if (!connection.isAuthenticated) {
login()
}
}
override fun connectionClosed() {
if (isToasted)
Handler(Looper.getMainLooper()).post(Runnable {
// TODO Auto-generated method stub
Toast.makeText(
context, "ConnectionCLosed!",
Toast.LENGTH_SHORT
).show()
})
Log.d("xmpp", "ConnectionCLosed!")
connected = false
chat_created = false
loggedin = false
}
override fun connectionClosedOnError(arg0: Exception) {
if (isToasted)
Handler(Looper.getMainLooper()).post(Runnable {
Toast.makeText(
context, "ConnectionClosedOn Error!!",
Toast.LENGTH_SHORT
).show()
})
Log.d("xmpp", "ConnectionClosedOn Error!")
connected = false
chat_created = false
loggedin = false
}
登录ejabberd服务器:
fun login() {
try {
connection?.login(loginUser, passwordUser)
Log.i("LOGIN", "Yey! We're connected to the Xmpp server!")
} catch (e: XMPPException) {
e.printStackTrace()
} catch (e: SmackException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
}
}
Logcat:
D/SMACK: RECV (0): <?xml version='1.0'?><stream:stream id='1777473137180053616' version='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' from='localhost' xmlns='jabber:client'>
2019-04-29 13:25:40.247 30893-30976/shop.com.letsshop D/SMACK: RECV (0): <stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><required/></starttls></stream:features>
2019-04-29 13:25:40.249 30893-30974/shop.com.letsshop E/(onCreate): SMACKException: SSL/TLS required by server but disabled in client
2019-04-29 13:25:40.251 30893-30976/shop.com.letsshop W/AbstractXMPPConnection: Connection XMPPTCPConnection[not-authenticated] (0) closed with error
org.jivesoftware.smack.SmackException$SecurityRequiredByServerException: SSL/TLS required by server but disabled in client
at org.jivesoftware.smack.tcp.XMPPTCPConnection.afterFeaturesReceived(XMPPTCPConnection.java:928)
at org.jivesoftware.smack.AbstractXMPPConnection.parseFeatures(AbstractXMPPConnection.java:1446)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1100(XMPPTCPConnection.java:149)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1048)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:980)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:996)
at java.lang.Thread.run(Thread.java:764)
2019-04-29 13:25:40.252 30893-30976/shop.com.letsshop D/xmpp: ConnectionClosedOn Error!
经过多次努力,我找到了解决方案:)
MyXmpp类:
val serviceName = JidCreate.domainBareFrom("localhost")// if user is register as admin@localhost ,you should have to take only string after "@" i.e localhost
val config = XMPPTCPConnectionConfiguration.builder()
config.setSecurityMode(ConnectionConfiguration.SecurityMode.required);
config.setXmppDomain(serviceName);
config.setHostAddress( InetAddress.getByName("192.168.0.101"))// your server ip address or for local host ,pc ip address
config.setPort(5222)
config.setDebuggerEnabled(true)
val sslContext = getSSLContext()// setting ssl
config.setCustomSSLContext(sslContext)
SASLAuthentication.blacklistSASLMechanism("SCRAM-SHA-1")
SASLAuthentication.blacklistSASLMechanism("DIGEST-MD5")
SASLAuthentication.unBlacklistSASLMechanism("PLAIN")
XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true)
XMPPTCPConnection.setUseStreamManagementDefault(true)
connection = XMPPTCPConnection(config.build())
connection?.login("admin", "localhost")//ejabber server login id .if you have admin@localhost then take only admin as a username . password i am having as localhost.
启用SSL:
@Throws(IOException::class,
CertificateException::class, NoSuchAlgorithmException::class, KeyStoreException::class, KeyManagementException::class)
private fun getSSLContext():SSLContext{
var cf: CertificateFactory? =null
try {
cf = CertificateFactory.getInstance("X.509");
} catch (e:CertificateException) {
Log.d("ca", "ca=" + e.message);
}
var input = context.getResources().openRawResource(R.raw.my_keystore); // R.raw.chain is CA Root Certificate added in RAW resources folder
var caInput = BufferedInputStream(input);
var ca:Certificate?=null
try {
ca = cf!!.generateCertificate(caInput)
// Log.d("ca", "ca=" + ((X509Certificate) ca).getSubjectDN())
}
catch (e:Exception){
Log.e("ca", e.message);
}
finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
var keyStoreType = KeyStore.getDefaultType();
var keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
var sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext;
}
在这里我卡住了:如何找到my_keystore。然后我在ejabbered的server.pem文件中找到你发现的私钥,我必须在客户端粘贴密钥(Android Studio-> res-> raw(文件夹) - > my_keystore(制作一个这样的空文件))即在my_keystore文件中。这是到达server.pem的完整路径。 /opt/ejabberd/conf