Saturday, August 29, 2020

Mutual TLS Authentication


Summary

This post will cover the mutual TLS/client-side certificate approach to API authentication.  This is an authentication scheme that's suitable for machine to machine authentication of a limited number of clients.  I'll demonstrate the approach with Node.js implementations of the server and client using self-signed certificates.

Message Flow

Diagram  below depicting the message exchanges (from a CURL session) for a mutual TLS authentication.



Generating Self-Signed Certs

Below is a sequence of OpenSSL commands to generate the server-side private key and self-signed public certificate, the client-side private key and certificate signing request, and finally client-side certificate signing by the server-side cert.

#generate server private key and cert
openssl req -x509 -newkey rsa:4096 -keyout serverKey.pem -out serverCert.pem -nodes -days 365 -subj "/CN=localhost"

#generate client private key and cert signing request
openssl req -newkey rsa:4096 -keyout clientKey.pem -out clientCsr.pem -nodes -subj "/CN=Client"

#sign client cert
openssl x509 -req -in clientCsr.pem -CA serverCert.pem -CAkey serverKey.pem -out clientCert.pem -set_serial 01 -days 365

Server Snippet

Node.js implementation of a REST server that will request mutual TLS/client-side cert. Highlighted areas are of note for mutual TLS.

const https = require('https');
const express = require('express');
const fs = require('fs');

const port = 8443;
const key = fs.readFileSync('serverKey.pem');
const cert = fs.readFileSync('serverCert.pem');
const options = {
        key: key,
        cert: cert,
        requestCert: true,
        ca: [cert]
};

let kvpStore = {};

const app = express();
app.use(express.json());

//create
app.post('/kvp', (req, res) => {
    const key = req.body.key;
    const value = req.body.value;
    if (key && value) {
        if (key in kvpStore) {
            res.status(400).json({error: 'kvp already exists'});
        }
        else {
            kvpStore[key] = value;
            res.status(201).json({key: key, value: kvpStore[key]});
        }
    } 
    else {
        res.status(400).json({error: 'missing key value pair'});
    }   
});

CURL Client Commands

#CREATE
curl -v -k --key clientKey.pem --cert clientCert.pem -H "Content-Type: application/json" -d '{"key":"1", "value":"abc"}' https://localhost:8443/kvp

#RETRIEVE
curl -v -k --key clientKey.pem --cert clientCert.pem https://localhost:8443/kvp/1

#UPDATE
curl -v -k --key clientKey.pem --cert clientCert.pem -X PUT -H "Content-Type: application/json" -d '{"key":"1", "value":"def"}' https://localhost:8443/kvp

#DELETE
curl -v -k --key clientKey.pem --cert clientCert.pem -X DELETE https://localhost:8443/kvp/1

Client Snippet

Node.js implementation of REST client supporting mutual TLS.  Again, highlighted areas depicting where mutual TLS-specific configuration is necessary.

const https = require('https');
const fs = require('fs');
const fetch = require('node-fetch');

const key = fs.readFileSync('clientKey.pem');
const cert = fs.readFileSync('clientCert.pem');
const options = {
        key: key,
        cert: cert,
        rejectUnauthorized: false
};
const url = 'https://localhost:8443/kvp/';
const tlsAgent = new https.Agent(options)

async function create(kvp) {
    const response = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(kvp),
        headers: {'Content-Type': 'application/json'},
        agent: tlsAgent
    });

    const json = await response.json();
    console.log(`CREATE - ${response.status} ${JSON.stringify(json)}`);
}

Source

https://github.com/joeywhelan/mutualtls

Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Saturday, August 1, 2020

Dialogflow, InContact Chat, BlueJeans Video Chat Integration


Summary

This post is a continuation of this one covering Dialogflow and InContact chat integration.  BlueJeans video chat will be added to that same framework in this post.

Architecture

I use Google's Cloud Storage to host a static website consisting of a simple HTML page with Javascript integrations to Google Cloud Functions.  Those functions provide CORS management and API key hiding for API calls to Dialogflow, InContact, and BlueJeans.


 

Application Flow

 



Execution

Screenshots of Client and Agent interfaces during a contrived exchange below.


Copyright ©1993-2024 Joey E Whelan, All rights reserved.