Skip to content

Commit

Permalink
HA network detection, and authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
rentallect committed Sep 9, 2024
1 parent 37407da commit 9d26446
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 53 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
},
"dependencies": {
"@openziti/libcrypto-js": "^0.21.0",
"@openziti/ziti-browzer-edge-client": "^0.6.2",
"@openziti/ziti-browzer-edge-client": "^0.7.0",
"asn1js": "^3.0.5",
"assert": "^2.0.0",
"async-mutex": "^0.5.0",
Expand Down
43 changes: 38 additions & 5 deletions src/channel/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,42 @@ class ZitiChannel {

}

/**
*
*/
async connectWithRetry(conn, retries = 10, backoff = 50) {
const self = this;

for (let attempt = 1; attempt <= retries; attempt++) {
try {
self._zitiContext.logger.debug(`ch.connectWithRetry() attempt ${attempt} starting - wssER[${this._edgeRouterHost}] conn[${conn.id}]`);

await self.connect(conn);

if (!isEqual(conn.state, ZitiEdgeProtocol.conn_state.Connected)) {
self._zitiContext.logger.debug(`ch.connectWithRetry() attempt ${attempt} failed - wssER[${this._edgeRouterHost}] conn[${conn.id}] state[${conn.state}]`);
throw new Error(`Connect attempt failed`);
}

return;
} catch (error) {
if (isEqual(attempt, retries)) {

self._zitiContext.emit('channelConnectFailEvent', {
serviceName: conn.data.serviceName
});

throw error; // rethrow the error after the final attempt
}

// Backoff: wait for some time before retrying
const delay = Math.min((backoff * Math.pow(2, attempt - 1)), 1000);
self._zitiContext.logger.debug(`ch.connectWithRetry() retrying in ${delay}ms - wssER[${this._edgeRouterHost}] conn[${conn.id}]`);
await self._zitiContext.delay(delay);
}
}
}

/**
* Connect specified Connection to associated Edge Router.
*
Expand Down Expand Up @@ -446,10 +482,6 @@ class ZitiChannel {

this._zitiContext.logger.warn(`ch._recvConnectResponse() conn[${conn.id}] failed to connect on ch[${this.id}]`);
conn.state = (ZitiEdgeProtocol.conn_state.Closed);

this._zitiContext.emit('channelConnectFailEvent', {
serviceName: expectedConn.data.serviceName
});
break;

case ZitiEdgeProtocol.content_type.StateConnected:
Expand Down Expand Up @@ -1127,7 +1159,8 @@ class ZitiChannel {
// let dbgStr = m1.substring(0, len);
// this._zitiContext.logger.trace("recv <- data (first 2000): %s", dbgStr);

} catch (e) { }
} catch (e) {
}

bodyView = unencrypted_data.message;
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/channel/wasm-tls-connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ import {Mutex, withTimeout, Semaphore} from 'async-mutex';
if (_connected) {

setTimeout((self) => {
self._zitiContext.logger.trace("ZitiWASMTLSConnection.connected(): after timeout");
// self._zitiContext.logger.trace("ZitiWASMTLSConnection.connected(): after timeout");
self._connected = true;
}, 500, this);

Expand Down Expand Up @@ -239,7 +239,7 @@ import {Mutex, withTimeout, Semaphore} from 'async-mutex';
* @param {*} arrayBuffer // ArrayBuffer
*/
async process(arrayBuffer) {
this._zitiContext.logger.trace(`ZitiWASMTLSConnection.process fd[${this.wasmFD}] encrypted data from the ER arrived <--- [${arrayBuffer}]`);
this._zitiContext.logger.trace(`ZitiWASMTLSConnection.process fd[${this.wasmFD}] encrypted data from the ER arrived <--- `, arrayBuffer);

await this._zitiContext.tls_enqueue(this._wasmInstance, this.wasmFD, arrayBuffer); // enqueue the encrypted data (place it in WASM memory)

Expand Down
6 changes: 6 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ const ZITI_CONSTANTS =
*/
'ZITI_EVENT_XGRESS_RX_NESTED_TLS': 'xgressEventNestedTLS',

/**
* High Availability (HA)
*/
'ZITI_HA_CONTROLLER': 'HA_CONTROLLER',
'ZITI_OIDC_AUTH': 'OIDC_AUTH',

};


Expand Down
123 changes: 82 additions & 41 deletions src/context/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ class ZitiContext extends EventEmitter {
this._tlsHandshakeLock = withTimeout(new Mutex(), 30 * 1000, new Error('timeout on _tlsHandshakeLock'));

this._fetchSemaphoreHTTP = new Semaphore( 8 );

//TEMP: we constrain HTTP requests that travel over nestedTLS to one-at-a-time for the moment.
// This will be removed as soon as I fix the TLS protocol collision issue that manifests
// when multiple HTTP requests are initiated simultaneously :(
this._fetchSemaphoreHTTPS = new Semaphore( 8 );

this._pkey = null;
Expand Down Expand Up @@ -161,6 +157,8 @@ class ZitiContext extends EventEmitter {
logger: this.logger,

})

this.controllerCapabilities = [];

}

Expand Down Expand Up @@ -746,60 +744,97 @@ class ZitiContext extends EventEmitter {
return result;
}


/**
* doAuthenticateWithOIDC
*
* Utilize Controller's HA OIDC endpoint to authenticate.
* This code exists here, inline, instead of being in the zitiBrowzerEdgeClient, because the controller's
* swagger spec doesn't include the new HA OIDC endpoint refs.
*/
async doAuthenticate() {
doAuthenticateWithOIDC(parameters) {

let self = this;

return new Promise( async (resolve, reject) => {
if (parameters === undefined) {
parameters = {};
}

// Use 'ext-jwt' style authentication, but allow for 'password' style (mostly for testing)
let method = (isNull(self.access_token)) ? 'password' : 'ext-jwt';
self.logger.trace(`ZitiContext.doAuthenticate(): method[${method}]`);
let deferred = self._zitiBrowzerEdgeClient.getDeferred();
let domain = self._zitiBrowzerEdgeClient.domain;

// Get an API session with Controller
let res = await self._zitiBrowzerEdgeClient.authenticate({
domain = domain.replace(`/edge/client/v1`, `/oidc/login/ext-jwt`); // don't hit edge-api, but instead, hit Controller's Zitadel endpoint

method: method,
let body = {},
queryParameters = {},
headers = {},
form = {};

auth: {
headers = self._zitiBrowzerEdgeClient.setAuthHeaders(headers);
headers['Accept'] = ['application/json'];
headers['Content-Type'] = ['application/json'];

username: self.updbUser,
password: self.updbPswd,
if (parameters['auth'] !== undefined) {
body = parameters['auth'];
}

configTypes: [
'ziti-tunneler-client.v1',
'intercept.v1',
'zrok.proxy.v1'
],
queryParameters = self._zitiBrowzerEdgeClient.mergeQueryParams(parameters, queryParameters);

envInfo: {
self._zitiBrowzerEdgeClient.request('POST', domain, parameters, body, headers, queryParameters, form, deferred);

// e.g.: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36'
arch: (typeof _ziti_realFetch !== 'undefined') ? window.navigator.userAgent : 'n/a',
return deferred.promise;
};

// e.g.: 'macOS', 'Linux', 'Windows'
os: (typeof _ziti_realFetch !== 'undefined') ? (typeof navigator.userAgentData !== 'undefined' ? navigator.userAgentData.platform : 'n/a') : 'n/a'
},

sdkInfo: {
type: self.sdkType,
version: self.sdkVersion,
branch: self.sdkBranch,
revision: self.sdkRevision,
},

}
}).catch((error) => {
self.logger.error( error );
});

return resolve( res );
/**
*
*/
async doAuthenticate() {

});
let self = this;

// the 'auth' body is common between the legacy and HA auth endpoints
let auth = {

configTypes: [
'ziti-tunneler-client.v1',
'intercept.v1',
'zrok.proxy.v1'
],

envInfo: {

// e.g.: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36'
arch: (typeof _ziti_realFetch !== 'undefined') ? window.navigator.userAgent : 'n/a',

// e.g.: 'macOS', 'Linux', 'Windows'
os: (typeof _ziti_realFetch !== 'undefined') ? (typeof navigator.userAgentData !== 'undefined' ? navigator.userAgentData.platform : 'n/a') : 'n/a'
},

sdkInfo: {
type: self.sdkType,
version: self.sdkVersion,
branch: self.sdkBranch,
revision: self.sdkRevision,
},

}

// If running in an HA network, utilize Controller's HA OIDC endpoint to authenticate...
if (this.controllerCapabilities.includes(ZITI_CONSTANTS.ZITI_HA_CONTROLLER) && this.controllerCapabilities.includes(ZITI_CONSTANTS.ZITI_OIDC_AUTH)) {
let res = await self.doAuthenticateWithOIDC({ auth: auth }).catch((error) => {
self.logger.error( error );
});
return res;
}
// ...otherwise, utilize Controller's "legacy"" endpoint to authenticate
else {
let method = (isNull(self.access_token)) ? 'password' : 'ext-jwt';
let res = await self._zitiBrowzerEdgeClient.authenticate({ method: method, auth: auth }).catch((error) => {
self.logger.error( error );
});
return res;
}
}

delay(time) {
Expand Down Expand Up @@ -1165,6 +1200,10 @@ class ZitiContext extends EventEmitter {

this.logger.info('Controller Version acquired: ', this._controllerVersion.version);

const {capabilities} = this._controllerVersion;
this.controllerCapabilities = capabilities;
this.logger.trace(`controllerCapabilities: ${this.controllerCapabilities}`);

return this._controllerVersion;
}

Expand Down Expand Up @@ -1770,7 +1809,9 @@ class ZitiContext extends EventEmitter {

// Initiate connection with Edge Router (creates Fabric session)
// if (conn.socket.isNew) {
await channelWithNearestEdgeRouter.connect(conn);
await channelWithNearestEdgeRouter.connectWithRetry(conn).catch(( error ) => {
this.logger.trace(`ctx.connect() conn[${conn.id}] error[${error.message}]`);
});
// }

if (conn.state == ZitiEdgeProtocol.conn_state.Connected) {
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1313,10 +1313,10 @@
"@types/emscripten" "^1.39.6"
"@wasmer/wasi" "^1.0.2"

"@openziti/ziti-browzer-edge-client@^0.6.2":
version "0.6.2"
resolved "https://registry.yarnpkg.com/@openziti/ziti-browzer-edge-client/-/ziti-browzer-edge-client-0.6.2.tgz#b6a2cb43e15edd3d585029f447a19bfbd0a3212f"
integrity sha512-NmfJmQtlGWkvuYmnO3WDOzRMJV38mZUosTMvZTTHIXr7xpdUs53liErzRovjt6gKV5rG5e5od0aq+r+dxMuv5w==
"@openziti/ziti-browzer-edge-client@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@openziti/ziti-browzer-edge-client/-/ziti-browzer-edge-client-0.7.0.tgz#9e4d75439fc6b40c9e9f15b48a2c7e825de78643"
integrity sha512-m7W9uEFIaXtVOXZ/dorbV/zMgCGfV0sK7SNAoyWLxIRyudikSbiW1Oo0f5jwyhsqDce9syXu/0qUdeAR+jwgcg==
dependencies:
superagent "^7.1.3"

Expand Down

0 comments on commit 9d26446

Please sign in to comment.