Skip to content

Commit

Permalink
Zowe Suite v2.17.0
Browse files Browse the repository at this point in the history
  • Loading branch information
zowe-robot authored Jul 2, 2024
2 parents d1460e0 + 7252bc1 commit f4fbf6b
Show file tree
Hide file tree
Showing 18 changed files with 552 additions and 2,901 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
4 changes: 2 additions & 2 deletions lib/swagger-catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const Promise = require('bluebird');
const zLuxUrl = require('./url')
const path = require('path');
const fs = require('fs');
const jsyaml = require('js-yaml');
const yaml = require('yaml');
const swaggerParser = require('swagger-parser')
const os = require('os');
const zluxUtil = require('./util');
Expand Down Expand Up @@ -201,7 +201,7 @@ function readSingleSwaggerFile (dirName, serviceName, serviceVersion) {
if (err) {
return reject(err);
}
let swaggerJson = jsyaml.safeLoad(fileContent);
let swaggerJson = yaml.parse(fileContent);
swaggerParser.validate(swaggerJson).then(function(valid) {
return resolve(swaggerJson)
}).catch(function(err) {
Expand Down
10 changes: 4 additions & 6 deletions lib/tomcatManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ unpack the wars ahead of time, so the symbolic links are the unpacked dirs
import { Path, TomcatConfig, TomcatShutdown, TomcatHttps, JavaServerManager, AppServerInfo } from './javaTypes';
import * as fs from 'graceful-fs';
import * as path from 'path';
import * as mkdirp from 'mkdirp';
import * as child_process from 'child_process';
//import * as xml2js from 'xml2js';
import * as yauzl from 'yauzl';
import * as utils from './util';
import * as rimraf from 'rimraf';

const log = utils.loggers.langManager;
const spawn = child_process.spawn;
Expand Down Expand Up @@ -63,7 +61,7 @@ export class TomcatManager implements JavaServerManager {

private makeRoot():Promise<void> {
return new Promise((resolve,reject)=> {
mkdirp(this.appdir, {mode: DIR_WRITE_MODE}, (err)=> {
fs.mkdir(this.appdir, {recursive: true, mode: DIR_WRITE_MODE}, (err)=> {
if (err) {
reject(err);
} else {
Expand Down Expand Up @@ -279,7 +277,7 @@ export class TomcatManager implements JavaServerManager {
log.info(`ZWED0092I`, this.id); //log.info(`Tomcat Manager ID=${this.id} stopping`);
TomcatManager.isWindows ? this.stopForWindows() : this.stopForUnix();
return new Promise((resolve, reject) => {
rimraf(this.appdir, (error)=> {
fs.rm(this.appdir, { recursive: true, force: true }, (error)=> {
if (error) {
reject(error);
} else {
Expand Down Expand Up @@ -368,7 +366,7 @@ export class TomcatManager implements JavaServerManager {
zipfile.on("entry", function(entry) {
if (entry.fileName.endsWith('/')) {
//directory
mkdirp(path.join(destPath,entry.fileName), {mode: DIR_WRITE_MODE}, (err)=> {
fs.mkdir(path.join(destPath,entry.fileName), {recursive: true, mode: DIR_WRITE_MODE}, (err)=> {
if (err) {
error = err;
zipfile.close();
Expand All @@ -380,7 +378,7 @@ export class TomcatManager implements JavaServerManager {
zipfile.readEntry(); //TODO is it correct to skip this?
} else {
//file
mkdirp(path.join(destPath,path.dirname(entry.fileName)), {mode: DIR_WRITE_MODE}, (err)=> {
fs.mkdir(path.join(destPath,path.dirname(entry.fileName)), {recursive: true, mode: DIR_WRITE_MODE}, (err)=> {
if (err) {
error = err;
zipfile.close();
Expand Down
23 changes: 15 additions & 8 deletions lib/translation-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

'use strict';
const path = require('path');
const fs = require('fs');
const jsonUtils = require('./jsonUtils.js');
const glob = require('glob');
const zluxUtil = require('./util');
const acceptLanguageParser = require('accept-language-parser');

Expand All @@ -31,15 +31,22 @@ const utilLog = zluxUtil.loggers.utilLogger;
*/
function loadTranslations(pluginLocation) {
const translationMaps = {};
const relativePath = 'web/assets/i18n';
const filePrefix = 'pluginDefinition.i18n.';
const fileExt = '.json';
const pattern = path.join(
pluginLocation,
relativePath,
`${filePrefix}*${fileExt}`
);
const files = glob.sync(pattern, {});
const folder = path.join(pluginLocation, 'web/assets/i18n');
let files = [];
try {
files = fs.readdirSync(folder)
.filter((filename)=> {
return filename.startsWith(filePrefix) && filename.endsWith(fileExt);
})
.map((filename)=> {
return path.join(folder, filename);
});
} catch (e) {
//A plugin may not have translations and that is OK.
return translationMaps;
}
for (const file of files) {
const basename = path.basename(file);
const languageCountry = basename.substring(
Expand Down
35 changes: 27 additions & 8 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ if (!global.COM_RS_COMMON_LOGGER) {

const path = require('path');
const fs = require('fs');
const util = require('node:util');
const Promise = require('bluebird');
const ipaddr = require('ipaddr.js');
const dns = require('dns');
const dnsLookup = Promise.promisify(dns.lookup);
const dnsLookup = util.promisify(dns.lookup);
const mergeUtils = require('../utils/mergeUtils');
const forge = require('node-forge');

Expand Down Expand Up @@ -138,9 +139,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 @@ -360,7 +362,12 @@ module.exports.uniqueIps = Promise.coroutine(function *uniqueIps(hostnames) {
if (typeof hostname == 'string') { //really... dnsLookup would not throw on a non-string such as false
try {
const ipAddress = yield dnsLookup(hostname);
set.add(ipAddress);
//This used to yield a string and now yields an object that contains a string within.
if (typeof ipAddress == 'string') {
set.add(ipAddress);
} else {
set.add(ipAddress.address);
}
} catch (e) {
loggers.network.warn(`ZWED0054W`, hostname); //loggers.network.warn(`Skipping invalid listener address=${hostname}`);
}
Expand Down Expand Up @@ -496,13 +503,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
Loading

0 comments on commit f4fbf6b

Please sign in to comment.