All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datamountaineer.streamreactor.connect.coap.connection.DTLSConnectionFn.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 Datamountaineer.
 *
 * 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 com.datamountaineer.streamreactor.connect.coap.connection

import java.io.FileInputStream
import java.net.{ConnectException, InetAddress, InetSocketAddress, URI}
import java.security.cert.Certificate
import java.security.{KeyStore, PrivateKey}

import com.datamountaineer.streamreactor.connect.coap.configs.{CoapConstants, CoapSetting}
import com.typesafe.scalalogging.slf4j.StrictLogging
import org.apache.kafka.common.config.ConfigException
import org.eclipse.californium.core.coap.CoAP
import org.eclipse.californium.core.CoapClient
import org.eclipse.californium.core.network.CoapEndpoint
import org.eclipse.californium.core.network.config.NetworkConfig
import org.eclipse.californium.scandium.DTLSConnector
import org.eclipse.californium.scandium.config.DtlsConnectorConfig
import org.eclipse.californium.scandium.dtls.cipher.CipherSuite
import org.eclipse.californium.scandium.dtls.pskstore.InMemoryPskStore

/**
  * Created by [email protected] on 27/12/2016. 
  * stream-reactor
  */
object DTLSConnectionFn extends StrictLogging {
  def apply(setting: CoapSetting): CoapClient = {

    val configUri = new URI(setting.uri)

    val uri: URI = configUri.getHost match {
      case CoapConstants.COAP_DISCOVER_IP4 => discoverServer(CoapConstants.COAP_DISCOVER_IP4_ADDRESS, configUri)
      case CoapConstants.COAP_DISCOVER_IP6 => discoverServer(CoapConstants.COAP_DISCOVER_IP6_ADDRESS, configUri)
      case _ => configUri
    }

    val client: CoapClient = new CoapClient(uri)
    val addr = new InetSocketAddress(InetAddress.getByName(setting.bindHost), setting.bindPort)
    val builder = new DtlsConnectorConfig.Builder
    builder.setAddress(addr)

    if (uri.getScheme.equals(CoAP.COAP_SECURE_URI_SCHEME)) {

      //Use SSL
      if (setting.identity.isEmpty) {
        val keyStore = KeyStore.getInstance("JKS")
        val inKey = new FileInputStream(setting.keyStoreLoc)
        keyStore.load(inKey, setting.keyStorePass.value().toCharArray())
        inKey.close()

        val trustStore = KeyStore.getInstance("JKS")
        val inTrust = new FileInputStream(setting.trustStoreLoc)
        trustStore.load(inTrust, setting.trustStorePass.value().toCharArray())
        inTrust.close()

        val certificates: Array[Certificate] = setting.certs.map(c => trustStore.getCertificate(c))
        val privateKey = keyStore.getKey(setting.chainKey, setting.keyStorePass.value().toCharArray).asInstanceOf[PrivateKey]
        val certChain = keyStore.getCertificateChain(setting.chainKey)

        builder.setIdentity(privateKey, certChain, true)
        builder.setTrustStore(certificates)

      } else {

        val psk = new InMemoryPskStore()
        psk.setKey(setting.identity, setting.secret.value().getBytes())
        psk.addKnownPeer(addr, setting.identity, setting.secret.value().getBytes())
        builder.setPskStore(psk)

        if (setting.privateKey.isDefined) {
          builder.setSupportedCipherSuites(Array[CipherSuite](CipherSuite.TLS_PSK_WITH_AES_128_CCM_8, CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256))
          builder.setIdentity(setting.privateKey.get, setting.publicKey.get)
        }
      }

      client.setEndpoint(new CoapEndpoint(new DTLSConnector(builder.build()), NetworkConfig.getStandard))
    }
    client.setURI(s"${setting.uri}/${setting.target}")
  }

  /**
    * Discover servers on the local network
    * and return the first one
    *
    * @param address The multicast address (ip4 or ip6)
    * @param uri  The original URI
    * @return A new URI of the server
    **/
  def discoverServer(address: String, uri: URI): URI = {
    val client = new CoapClient(s"${uri.getScheme}://$address:${uri.getPort.toString}/.well-known/core")
    client.useNONs()
    val response = client.get()

    if (response != null) {
      logger.info(s"Discovered Server ${response.advanced().getSource.toString}.")
      new URI(uri.getScheme,
        uri.getUserInfo,
        response.advanced().getSource.getHostName,
        response.advanced().getSourcePort,
        uri.getPath,
        uri.getQuery,
        uri.getFragment)
    } else {
      logger.error(s"Unable to find any servers on local network with multicast address $address.")
      throw new ConnectException(s"Unable to find any servers on local network with multicast address $address.")
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy