Skip to content

Commit

Permalink
Merge pull request #544 from zowe/bugfix/v2/attls
Browse files Browse the repository at this point in the history
Fix ability to use attls
  • Loading branch information
1000TurquoisePogs authored May 28, 2024
2 parents 806be15 + f0d5298 commit d2a02a2
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 43 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
All notable changes to the Zlux Server Framework package will be documented in this file..
This repo is part of the app-server Zowe Component, and the change logs here may appear on Zowe.org in that section.

## 2.17.0
- Enhancement: Added function `isClientAttls(zoweConfig)` within `libs/util.js`. Whenever a plugin makes a network request, it should always use this to determine if a normally HTTPS request should instead be made as HTTP due to AT-TLS handling the TLS when enabled. (#544)
- Bugfix: Fixed function `isServerAttls(zoweConfig)` within `libs/util.js`, which was preventing using AT-TLS with app-server. (#544)

## 2.15.0
- Bugfix: App-server could not run in HTTP mode for AT-TLS setup because it was not able to merge HTTPS and HTTP addresses. (#984)

Expand Down
19 changes: 11 additions & 8 deletions lib/apiml.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const Promise = require("bluebird");
const eureka = require('@rocketsoftware/eureka-js-client').Eureka;
const zluxUtil = require('./util');
const https = require('https');
const http = require('http');

const log = zluxUtil.loggers.apiml;

Expand Down Expand Up @@ -77,10 +78,10 @@ const MEDIATION_LAYER_INSTANCE_DEFAULTS = (zluxProto, zluxHostname, zluxPort) =>
}
}};

function ApimlConnector({ hostName, port, isHttps, discoveryUrls,
discoveryPort, tlsOptions, eurekaOverrides }) {
Object.assign(this, { hostName, port, isHttps, discoveryUrls,
discoveryPort, tlsOptions, eurekaOverrides });
function ApimlConnector({ hostName, port, discoveryUrls,
discoveryPort, tlsOptions, eurekaOverrides, isClientAttls }) {
Object.assign(this, { hostName, port, discoveryUrls,
discoveryPort, tlsOptions, eurekaOverrides, isClientAttls });
this.vipAddress = hostName;
}

Expand Down Expand Up @@ -121,8 +122,10 @@ ApimlConnector.prototype = {
}

let data = [];

let httpModule = this.isClientAttls ? http : https;

const req = https.request(options, (res) => {
const req = httpModule.request(options, (res) => {
res.on('data', (chunk) => data.push(chunk));
res.on('end', () => {
log.debug(`Query rc=`,res.statusCode);
Expand Down Expand Up @@ -165,10 +168,10 @@ ApimlConnector.prototype = {
// If the HTTP port is set to 0 then the API ML doesn't load zlux
httpPort: Number(this.port),
httpsPort: Number(this.port),
httpEnabled: !this.isHttps,
httpsEnabled: this.isHttps
httpEnabled: false,
httpsEnabled: true
};
const proto = this.isHttps? 'https' : 'http';
const proto = 'https';

log.debug("ZWED0141I", proto, this.port); //"Protocol:", proto, "Port", port);
log.debug("ZWED0142I", JSON.stringify(protocolObject)); //"Protocol Object:", JSON.stringify(protocolObject));
Expand Down
18 changes: 13 additions & 5 deletions lib/apimlStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ import { AxiosInstance } from 'axios';
let apimlClient: AxiosInstance;

export function configure(settings: ApimlStorageSettings) {
apimlClient = axios.create({
baseURL: `https://${settings.host}:${settings.port}`,
httpsAgent: new https.Agent(settings.tlsOptions)
});
if (settings.isHttps) {
apimlClient = axios.create({
baseURL: `https://${settings.host}:${settings.port}`,
httpsAgent: new https.Agent(settings.tlsOptions)
});
} else {
apimlClient = axios.create({
baseURL: `https://${settings.host}:${settings.port}`,
httpAgent: new http.Agent()
});
}
}

export function isConfigured(): boolean {
Expand All @@ -30,6 +37,7 @@ export interface ApimlStorageSettings {
host: string;
port: number;
tlsOptions: https.AgentOptions;
isHttps?: boolean;
}


Expand Down Expand Up @@ -375,4 +383,4 @@ class ApimlStorage {
SPDX-License-Identifier: EPL-2.0
Copyright Contributors to the Zowe Project.
*/
*/
3 changes: 2 additions & 1 deletion lib/auth-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ AuthManager.prototype = {
plugin,
this.configuration,
componentConfig,
new AuthPluginContext(plugin, tlsOptions));
new AuthPluginContext(plugin, tlsOptions),
config);
// at this time we should have resolved plugin configuration to have a
// nice list of info about what we are using to authenticate against
if ((typeof authenticationHandler.authenticate) !== 'function') {
Expand Down
11 changes: 6 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,10 @@ Server.prototype = {
this.apiml = new ApimlConnector({
hostName: webAppOptions.hostname,
port: this.port,
isHttps: util.isServerHttps(this.zoweConfig),
discoveryUrls: apimlConfig.server.discoveryUrls || [`https://${apimlConfig.server.hostname}:${apimlConfig.server.port}/eureka/`],
tlsOptions: this.tlsOptions,
eurekaOverrides: apimlConfig.eureka
eurekaOverrides: apimlConfig.eureka,
isClientAttls: util.isClientAttls(this.zoweConfig)
});
yield this.apiml.setBestIpFromConfig(this.componentConfig.node);
yield this.apiml.registerMainServerInstance();
Expand Down Expand Up @@ -263,7 +263,7 @@ Server.prototype = {

bootstrapLogger.info('ZWED0302I', util.isHaMode() ? 'enabled' : 'disabled'); // "HA mode is %s"
if (apimlConfig.cachingService?.enabled) {
this.configureApimlStorage(apimlConfig);
this.configureApimlStorage(apimlConfig, util.isClientAttls(this.zoweConfig));
}

const plugins = yield this.loadPlugins();
Expand Down Expand Up @@ -335,11 +335,12 @@ Server.prototype = {
return yield this.pluginLoader.loadPlugins();
}),

configureApimlStorage(apimlConfig) {
configureApimlStorage(apimlConfig, isHttps) {
apimlStorage.configure({
host: apimlConfig.server.gatewayHostname,
port: apimlConfig.server.gatewayPort,
tlsOptions: this.tlsOptions
tlsOptions: this.tlsOptions,
isHttps: isHttps
});
bootstrapLogger.info(`ZWED0300I`); // Caching Service configured
},
Expand Down
25 changes: 19 additions & 6 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,10 @@ module.exports.getAgentRequestOptions = function(zoweConfig, tlsOptions, include
zoweConfig.components['app-server'].node.mediationLayer &&
zoweConfig.components['app-server'].node.mediationLayer.server);

const isHttps = useApiml ||
(agentConfig.https && agentConfig.https.port) ||
(agentConfig.http && agentConfig.http.port && agentConfig.http.attls);
const isHttps = !isClientAttls(zoweConfig) &&
(useApiml ||
(agentConfig.https && agentConfig.https.port) ||
(agentConfig.http && agentConfig.http.port && agentConfig.http.attls));
if (isHttps && !tlsOptions) {
console.log('return undefined, ishttps without tlsoptions');
return undefined;
Expand Down Expand Up @@ -496,13 +497,25 @@ const isHaMode = module.exports.isHaMode = function () {
return isHaMode;
}

//TODO, ATTLS
module.exports.isServerHttps = function(zoweConfig) {
return !!zoweConfig.components['app-server'].node.https;
return Number.isInteger(zoweConfig.components['app-server'].node.https?.port);
}

function isClientAttls(zoweConfig) {
let clientGlobalAttls = zoweConfig.zowe.network?.client?.tls?.attls;
let clientLocalAttls = zoweConfig.components['app-server'].zowe?.network?.client?.tls?.attls;
let clientAttls = clientGlobalAttls || clientLocalAttls;
if ((clientGlobalAttls !== false) && (clientLocalAttls !== false) && (!clientAttls)) {
// If client attls not explicitly false OR truthy, have client follow server attls variable. it simplifies common case in which users want both.
return zoweConfig.zowe.network?.server?.tls?.attls || zoweConfig.components['app-server'].zowe?.network?.server?.tls?.attls;
} else {
return clientAttls;
}
}
module.exports.isClientAttls = isClientAttls;

module.exports.getBestPort = function(zoweConfig) {
return zoweConfig.components['app-server'].node.https
return zoweConfig.components['app-server'].node.https?.port
? zoweConfig.components['app-server'].node.https.port
: zoweConfig.components['app-server'].node.http.port;
}
Expand Down
13 changes: 8 additions & 5 deletions lib/webapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ WebServiceHandle.prototype = {
requestOptions.hostname = this.service.host;
requestOptions.port = this.service.port;
requestOptions.path = this.service.urlPrefix;
requestOptions.protocol = this.service.isHttps ? 'https:': 'http:';
requestOptions.protocol = !this.environment.isClientAttls && this.service.isHttps ? 'https:': 'http:';
} else {
requestOptions.hostname = this.environment.agentRequestOptions.host;
requestOptions.port = this.environment.agentRequestOptions.port;
Expand Down Expand Up @@ -1037,7 +1037,7 @@ WebServiceHandle.prototype = {
} else {
routingLog.debug(`Call loopback path=%s`, requestOptions.path);
//loopback call to get to router
httpOrHttps = this.environment.loopbackConfig.isHttps ? https : http;
httpOrHttps = !this.environment.isClientAttls && this.environment.loopbackConfig.isHttps ? https : http;
}
}
//if not internal routing
Expand Down Expand Up @@ -1400,7 +1400,8 @@ function WebApp(options){
this.setValidReferrers();
this.wsEnvironment = {
loopbackConfig: this.loopbackConfig,
agentRequestOptions: zluxUtil.getAgentRequestOptions(options.zoweConfig, options.tlsOptions, false)
agentRequestOptions: zluxUtil.getAgentRequestOptions(options.zoweConfig, options.tlsOptions, false),
isClientAttls: zluxUtil.isClientAttls(options.zoweConfig)
}
this.auth = options.auth;
this.configLocation = options.configLocation;
Expand Down Expand Up @@ -1503,7 +1504,7 @@ WebApp.prototype = {
host = requestOptions.host;
port = requestOptions.port;
options.urlPrefix = requestOptions.path;
options.isHttps = requestOptions.protocol == 'https:';
options.isHttps = !zluxUtil.isClientAttls(this.options.zoweConfig) && (requestOptions.protocol == 'https:');
options.requestProcessingOptions = requestOptions.requestProcessingOptions;
}

Expand All @@ -1522,6 +1523,7 @@ WebApp.prototype = {
let tlsOptions = Object.assign({}, this.options.tlsOptions);
delete tlsOptions.key;
delete tlsOptions.cert;
isHttps = !zluxUtil.isClientAttls(this.options.zoweConfig) && isHttps;
installLog.info(`ZWED0053I`, `${isHttps? 'HTTPS' : 'HTTP'}`, `${pluginID}:${serviceName}`, `${host}:${port}/${urlPrefix}`); //installLog.info(`Setting up ${isHttps? 'HTTPS' : 'HTTP'} proxy ` +`(${pluginID}:${serviceName}) to destination=${host}:${port}/${urlPrefix}`);
let myProxy = proxy.makeSimpleProxy(host, port, {
urlPrefix,
Expand Down Expand Up @@ -1785,6 +1787,7 @@ WebApp.prototype = {
},

_makeRouter: function *(service, plugin, pluginContext, pluginChain) {
const isHttps = !this.wsEnvironment.isClientAttls && service.isHttps;
const serviceRouterWithMiddleware = pluginChain.slice();
serviceRouterWithMiddleware.push(commonMiddleware.injectServiceDef(
service));
Expand Down Expand Up @@ -1840,7 +1843,7 @@ WebApp.prototype = {
case "external":
// installLog.info(`${plugin.identifier}: installing external proxy at ${subUrl}`);
router = this.makeExternalProxy(service.host, service.port,
service.urlPrefix, service.isHttps,
service.urlPrefix, isHttps,
undefined, plugin.identifier, service.name);
break;
default:
Expand Down
2 changes: 1 addition & 1 deletion lib/webserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ WebServer.prototype = {
if (nodeConfig.http && nodeConfig.http.port) {
this.httpOptions = {};
}
if (nodeConfig.https && nodeConfig.https.port) {
if (typeof nodeConfig.https == 'object') {
let options = nodeConfig.https;
this.httpsOptions = {};
if (typeof nodeConfig.allowInvalidTLSProxy == 'boolean') {
Expand Down
27 changes: 19 additions & 8 deletions plugins/sso-auth/lib/apimlHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@

const Promise = require('bluebird');
const https = require('https');
const http = require('http');
const fs = require('fs');
const zluxUtil = require('../../../lib/util');


/*495 minutes default session length for zosmf
* TODO: This is the session length of a zosmf session according to their documentation.
Expand Down Expand Up @@ -52,11 +55,19 @@ function readUtf8FilesToArray(fileArray) {


class ApimlHandler {
constructor(pluginDef, pluginConf, serverConf, context) {
constructor(pluginDef, pluginConf, componentConf, context, zoweConf) {
this.logger = context.logger;
this.apimlConf = serverConf.node.mediationLayer.server;
this.apimlConf = componentConf.node.mediationLayer.server;
this.gatewayUrl = `https://${this.apimlConf.gatewayHostname}:${this.apimlConf.gatewayPort}`;
this.httpsAgent = new https.Agent(context.tlsOptions);
this.isHttps = !zluxUtil.isClientAttls(zoweConf);
if (this.isHttps) {
this.httpsAgent = new https.Agent(context.tlsOptions);
this.httpModule = https;
} else {
this.httpAgent = new http.Agent();
this.httpModule = http;
}

}

logout(request, sessionState) {
Expand All @@ -77,7 +88,7 @@ class ApimlHandler {
agent: this.httpsAgent
}
this.logger.debug(`Sending logout request for ${sessionState.username} to path=${options.path}`);
const req = https.request(options, (res) => {
const req = this.httpModule.request(options, (res) => {
let data = [];
res.on('data', (d) => {data.push(d)});
res.on('end', () => {
Expand Down Expand Up @@ -223,7 +234,7 @@ class ApimlHandler {

let data = [];
this.logger.debug(`Sending query token request to path=${options.path}`);
const req = https.request(options, (res) => {
const req = this.httpModule.request(options, (res) => {
res.on('data', (chunk) => data.push(chunk));
res.on('end', () => {
this.logger.debug(`Query rc=`,res.statusCode);
Expand Down Expand Up @@ -263,7 +274,7 @@ class ApimlHandler {

const options = this.makeOptions('/gateway/api/v1/auth/login','POST', undefined, data.length);
this.logger.debug(`Sending login request for ${request.body.username} to path=${options.path}`);
const req = https.request(options, (res) => {
const req = this.httpModule.request(options, (res) => {
res.on('data', (d) => {});
res.on('end', () => {
this.logger.debug(`Login rc=`,res.statusCode);
Expand Down Expand Up @@ -400,6 +411,6 @@ class ApimlHandler {
}
}

module.exports = function(pluginDef, pluginConf, serverConf, context) {
return new ApimlHandler(pluginDef, pluginConf, serverConf, context);
module.exports = function(pluginDef, pluginConf, componentConf, context, zoweConf) {
return new ApimlHandler(pluginDef, pluginConf, componentConf, context, zoweConf);
}
8 changes: 4 additions & 4 deletions plugins/sso-auth/lib/ssoAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function cleanupSessionGeneric(sessionState) {
delete sessionState.sessionExpTime;
}

function SsoAuthenticator(pluginDef, pluginConf, serverConf, context) {
function SsoAuthenticator(pluginDef, pluginConf, serverConf, context, zoweConf) {
this.usingApiml = doesApimlExist(serverConf);
this.usingZss = doesZssExist(serverConf);

Expand All @@ -65,7 +65,7 @@ function SsoAuthenticator(pluginDef, pluginConf, serverConf, context) {
this.logger = context.logger;
this.categories = ['saf'];
if (this.usingApiml) {
this.apimlHandler = apimlHandlerFactory(pluginDef, pluginConf, serverConf, context);
this.apimlHandler = apimlHandlerFactory(pluginDef, pluginConf, serverConf, context, zoweConf);
this.categories.push('apiml');
}

Expand Down Expand Up @@ -325,6 +325,6 @@ SsoAuthenticator.prototype = {
}
};

module.exports = function (pluginDef, pluginConf, serverConf, context) {
return Promise.resolve(new SsoAuthenticator(pluginDef, pluginConf, serverConf, context));
module.exports = function (pluginDef, pluginConf, serverConf, context, zoweConf) {
return Promise.resolve(new SsoAuthenticator(pluginDef, pluginConf, serverConf, context, zoweConf));
}

0 comments on commit d2a02a2

Please sign in to comment.