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

dev.galasa.zossecurity.internal.ZosSecurityImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright contributors to the Galasa project
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package dev.galasa.zossecurity.internal;

import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.net.URI;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.PrincipalUtil;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

import dev.galasa.ICredentials;
import dev.galasa.ICredentialsUsernamePassword;
import dev.galasa.framework.spi.DynamicStatusStoreException;
import dev.galasa.framework.spi.IDynamicStatusStoreKeyAccess;
import dev.galasa.framework.spi.IDynamicStatusStoreService;
import dev.galasa.framework.spi.IFramework;
import dev.galasa.framework.spi.creds.CredentialsException;
import dev.galasa.http.HttpClientException;
import dev.galasa.http.HttpClientResponse;
import dev.galasa.http.IHttpClient;
import dev.galasa.http.spi.IHttpManagerSpi;
import dev.galasa.zos.IZosImage;
import dev.galasa.zos.ZosManagerException;
import dev.galasa.zos.spi.IZosManagerSpi;
import dev.galasa.zosfile.IZosFileHandler;
import dev.galasa.zosfile.ZosFileManagerException;
import dev.galasa.zosfile.spi.IZosFileSpi;
import dev.galasa.zossecurity.IZosCertificate;
import dev.galasa.zossecurity.IZosCicsClassSet;
import dev.galasa.zossecurity.IZosIdMap;
import dev.galasa.zossecurity.IZosKerberosPrincipal;
import dev.galasa.zossecurity.IZosKeyring;
import dev.galasa.zossecurity.IZosPreDefinedProfile;
import dev.galasa.zossecurity.IZosProfile;
import dev.galasa.zossecurity.IZosSecurity;
import dev.galasa.zossecurity.IZosUserid;
import dev.galasa.zossecurity.KerberosInitiator;
import dev.galasa.zossecurity.KerberosToken;
import dev.galasa.zossecurity.ZosSecurityManagerException;
import dev.galasa.zossecurity.datatypes.RACFAccessType;
import dev.galasa.zossecurity.datatypes.RACFCertificateTrust;
import dev.galasa.zossecurity.datatypes.RACFCertificateType;
import dev.galasa.zossecurity.internal.properties.CicsSharedClassets;
import dev.galasa.zossecurity.internal.properties.CreateUserid;
import dev.galasa.zossecurity.internal.properties.KerberosDomainController;
import dev.galasa.zossecurity.internal.properties.KerberosRealm;
import dev.galasa.zossecurity.internal.properties.OutputReporting;
import dev.galasa.zossecurity.internal.properties.PredefinedProfiles;
import dev.galasa.zossecurity.internal.properties.ResourceReporting;
import dev.galasa.zossecurity.internal.properties.ServerApikey;
import dev.galasa.zossecurity.internal.properties.ServerUrl;
import dev.galasa.zossecurity.internal.properties.SetroptsDelay;
import dev.galasa.zossecurity.internal.properties.UseridDefaultGroup;
import dev.galasa.zossecurity.internal.properties.UseridDefaultGroups;
import dev.galasa.zossecurity.internal.properties.UseridPool;
import dev.galasa.zossecurity.internal.resources.RacfOutputProcessing;
import dev.galasa.zossecurity.internal.resources.ZosCertificateImpl;
import dev.galasa.zossecurity.internal.resources.ZosCicsClassSetImpl;
import dev.galasa.zossecurity.internal.resources.ZosCicsSharedClassSetImpl;
import dev.galasa.zossecurity.internal.resources.ZosIdMapImpl;
import dev.galasa.zossecurity.internal.resources.ZosKerberosClientPrincipalImpl;
import dev.galasa.zossecurity.internal.resources.ZosKerberosPrincipalImpl;
import dev.galasa.zossecurity.internal.resources.ZosKeyringImpl;
import dev.galasa.zossecurity.internal.resources.ZosPreDefinedProfileImpl;
import dev.galasa.zossecurity.internal.resources.ZosProfileImpl;
import dev.galasa.zossecurity.internal.resources.ZosUseridImpl;

public class ZosSecurityImpl implements IZosSecurity {

	private static final Log logger = LogFactory.getLog(ZosSecurityImpl.class);

	public enum HttpMethod {
		GET,
		PUT,
		POST,
		DELETE
	}
	
	public enum ResourceType {
		ZOS_CERTIFICATE("zoscertificate"),
		ZOS_CICS_CLASS_SET("zoscicsclassset"),
		ZOS_ID_MAP("zosidmap"),
		ZOS_KERBEROS_PRINCIPAL("zoskerberosprincipal"),
		ZOS_KEYRING("zoskeyring"),
		ZOS_PRE_DEFINED_PROFILE_PERMIT("zospredefinedprofilepermit"),
		ZOS_PROFILE("zosprofile"),
		ZOS_USERID("zosuserid");

		private String name;

		ResourceType(String name) {
			this.name = name;
		}
		
		public String getName() {
			return this.name; 
		}
	}
	
	public final static Pattern ZOS_CERTIFICATE_PATTERN                = Pattern.compile("^" + ResourceType.ZOS_CERTIFICATE.getName()                + ".run\\.(\\w+)\\.(\\w+)\\/(\\w+)\\/([^\\.]+)\\.sysplex\\.(\\w+)$");
	public final static Pattern ZOS_CICS_CLASS_SET_PATTERN             = Pattern.compile("^" + ResourceType.ZOS_CICS_CLASS_SET.getName()             + ".run\\.(\\w+)\\.(\\w+)\\.sysplex\\.(\\w+)$");
	public final static Pattern ZOS_ID_MAP_PATTERN                     = Pattern.compile("^" + ResourceType.ZOS_ID_MAP.getName()                     + ".run\\.(\\w+)\\.(\\w+)\\/([\\S]+)\\.sysplex\\.(\\w+)$");
	public final static Pattern ZOS_KERBEROS_PRINCIPAL_PATTERN         = Pattern.compile("^" + ResourceType.ZOS_KERBEROS_PRINCIPAL.getName()         + ".run\\.(\\w+)\\.([\\S]+)\\.sysplex\\.(\\w+)$");
	public final static Pattern ZOS_KEYRING_PATTERN                    = Pattern.compile("^" + ResourceType.ZOS_KEYRING.getName()                    + ".run\\.(\\w+)\\.(\\w+)\\/([\\S]+)\\.sysplex\\.(\\w+)$");
	public final static Pattern ZOS_PRE_DEFINED_PROFILE_PERMIT_PATTERN = Pattern.compile("^" + ResourceType.ZOS_PRE_DEFINED_PROFILE_PERMIT.getName() + ".run\\.(\\w+)\\.(\\w+)\\/([\\S]+)\\/(\\w+)\\.sysplex\\.(\\w+)$");
	public final static Pattern ZOS_PROFILE_PATTERN                    = Pattern.compile("^" + ResourceType.ZOS_PROFILE.getName()                    + ".run\\.(\\w+)\\.(\\w+)\\/([\\S]+)\\.sysplex\\.(\\w+)$");
	public final static Pattern ZOS_USERID_PATTERN                     = Pattern.compile("^" + ResourceType.ZOS_USERID.getName()                     + ".run\\.(\\w+)\\.(\\w+)\\.sysplex\\.(\\w+)$");
	
	private IFramework framework;
	private final IDynamicStatusStoreService dss;
	private IZosManagerSpi zosManager;
	private IZosFileSpi zosFileManager;
	private IHttpManagerSpi httpManager;

	public final ArrayList preAllocatedCicsClassSets = new ArrayList<>();

	private final HashMap zossecServerClients = new HashMap();

	private final HashMap> classesRequiringRefresh = new HashMap>();

	private int certificateStoreNumber;
	private IZosUserid runUser;

	private IZosImage image;
	private IZosUserid imageUser;

	private boolean resourceReporting;
	private boolean outputReporting;
	private final Map zosSecurityServerQueryParams = new HashMap();

	private int setroptsDelay;
	private IZosFileHandler zosFileHandler;
	private String runDatasetHLQ;
	private List useridPool;
	private List cicsSharedClassSets;
	private boolean createUserid;
	private String useridDefaultGroup;
	private List useridDefaultGroups;

	public ZosSecurityImpl(ZosSecurityManagerImpl zosSecurityManagerImpl, IZosImage image) throws ZosSecurityManagerException {
		this.framework = zosSecurityManagerImpl.getFramework();
		this.dss = zosSecurityManagerImpl.getDss();
		this.zosManager = zosSecurityManagerImpl.getZosManager();
		this.zosFileManager = zosSecurityManagerImpl.getZosFileManager();
		this.httpManager = zosSecurityManagerImpl.getHttpManager();
		this.image = image;
		try {
			this.resourceReporting = ResourceReporting.get(getZosImage().getSysplexID());
			this.outputReporting = OutputReporting.get(getZosImage().getSysplexID());
			this.setroptsDelay = SetroptsDelay.get();
			this.useridPool = UseridPool.get(image.getSysplexID());
			this.cicsSharedClassSets = CicsSharedClassets.get(image.getSysplexID());
			this.createUserid = CreateUserid.get();
		} catch(ZosSecurityManagerException e) {
			throw new ZosSecurityManagerException("Unable to obtain manager properties", e);
		}

		if (this.resourceReporting) {
			logger.info("Resource Reporting has been enabled by configuration properties");
		}
		if (this.outputReporting) {
			logger.info("Output Reporting has been enabled by configuration properties");
		}		
		try {
			ICredentialsUsernamePassword creds = (ICredentialsUsernamePassword) getZosImage().getDefaultCredentials();
			this.imageUser = new ZosUseridImpl(this, creds.getUsername(), creds.getPassword(), null, image);
		} catch (ZosManagerException e) {
			throw new ZosSecurityManagerException("Problem getting default credentials fo image " + image.getImageID(), e);
		}
	}

	public ZosSecurityImpl(IFramework framework, IDynamicStatusStoreService dss, IHttpManagerSpi httpManager) throws ZosSecurityManagerException {
		this.framework = framework;
		this.dss = dss;
		this.zosManager = null;
		this.zosFileManager = null;
		this.httpManager = httpManager;
		this.image = null;
		this.resourceReporting = true;
		this.outputReporting = true;
		try {
			this.setroptsDelay = SetroptsDelay.get();
		} catch(ZosSecurityManagerException e) {
			throw new ZosSecurityManagerException("Unable to obtain manager properties", e);
		}
	}

	public IZosUserid allocateUserid(boolean runUser) throws ZosSecurityManagerException {
		IZosUserid userid = allocateUserid();
		if (runUser) {
			setRunUserid(userid); 
		}
		
		return userid;
	}

	@Override
	public IZosUserid getRunUserid() throws ZosSecurityManagerException {
		if (this.runUser == null) {
			this.runUser = this.imageUser;
		}
		return this.runUser;
	}

	@Override
	public IZosUserid allocateUserid() throws ZosSecurityManagerException {
		IZosUserid zosUserid;
		try {
			zosUserid = ZosUseridImpl.allocateUserId(this);
		} catch (ZosSecurityManagerException e) {
			throw new ZosSecurityManagerException("Problem allocating zOS Userid for image " + getZosImage(), e);
		}
		if (zosUserid == null) {
			throw new ZosSecurityManagerException("There are no zOS Userids available in the pool for image " + getZosImage());
		}

		return zosUserid;
	}

	@Override
	public void freeUserid(IZosUserid userid) throws ZosSecurityManagerException {
		try {
			((ZosUseridImpl) userid).free();
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Free of userid " + userid.getUserid() + "' failed", e);
		}
	}

	public IZosCicsClassSet allocateCicsClassSet(boolean allowAllAccess, boolean shared) throws ZosSecurityManagerException {
		IZosCicsClassSet zosClassset;
		if (shared) {
			zosClassset = allocateSharedCicsClassSet();
		} else {		
			zosClassset = allocateCicsClassSet();
		}
		if (allowAllAccess) {
			zosClassset.allowAllAccess();
		}
		return zosClassset;
	}

	@Override
	public IZosCicsClassSet allocateCicsClassSet() throws ZosSecurityManagerException {
		IZosCicsClassSet zosClassset;
		if (!preAllocatedCicsClassSets.isEmpty()) {
			zosClassset = preAllocatedCicsClassSets.remove(0);
		} else {
			zosClassset = (IZosCicsClassSet) ZosCicsClassSetImpl.allocateClassset(this);
			if (zosClassset == null) {
				throw new ZosSecurityManagerException("There are no zOS Classsets available in the pool for system '" + image + "'");
			}
		}

		return zosClassset;
	}

	private IZosCicsClassSet allocateSharedCicsClassSet() throws ZosSecurityManagerException {
		IZosCicsClassSet zosClassset = ZosCicsSharedClassSetImpl.allocateClassset(this, getZosImage());
		if (zosClassset == null) {
			throw new ZosSecurityManagerException("There are no zOS Shared Classsets available for system '" + image + "'");
		}

		return zosClassset;
	}

	@Override
	public void freeCicsClassSet(IZosCicsClassSet classSet) throws ZosSecurityManagerException {
		try {
			((ZosCicsClassSetImpl) classSet).free();
		} catch (ZosSecurityManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to free CICS Class Set", e);
		}
	}

	protected IZosPreDefinedProfile createPredefinedProfile(String className, String profile) throws ZosSecurityManagerException {
		String name = className + "/" + profile;

		logger.info("Associating Pre Defined Profile '" + name + "'");

		List validPredefinedProfiles;
		try {
			validPredefinedProfiles = PredefinedProfiles.get(getZosImage());
		} catch(ZosSecurityManagerException e) {
			throw new ZosSecurityManagerException("Unable to retrieve valid predefined profiles", e);
		}

		if (!validPredefinedProfiles.contains(name)) {
			throw new ZosSecurityManagerException("Requested predefined profile '" + name + "' is not authorised");
		}

		IZosImage image = null;


		try {
			image = getZosImage();
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to retrieve image for tag '" + image.getImageID() + "'", e);
		}

		return new ZosPreDefinedProfileImpl(this, image, className, profile);
	}

	@Override
	public IZosProfile createProfile(String className, String name, RACFAccessType uacc) throws ZosSecurityManagerException {
		return createProfile(getZosImage().getImageID(), className, name, null, uacc, true);
	}

	@Override
	public IZosProfile createProfile(String className, String name, RACFAccessType uacc, boolean refresh) throws ZosSecurityManagerException {
		return createProfile(getZosImage().getImageID(), className, name, null, uacc, refresh);
	}

	@Override
	public IZosProfile createProfile(String image, String className, String name, RACFAccessType uacc) throws ZosSecurityManagerException {
		return createProfile(image, className, name, null, uacc, true);
	}

	@Override
	public IZosProfile createProfile(String className, String name, Map args, RACFAccessType uacc) throws ZosSecurityManagerException {
		return createProfile(getZosImage().getImageID(), className, name, args, uacc, true);
	}

	@Override
	public IZosProfile createProfile(String image, String className, String name, RACFAccessType uacc, boolean refresh) throws ZosSecurityManagerException {
		return createProfile(image, className, name, null, uacc, refresh);
	}

	@Override
	public IZosProfile createProfile(String image, String className, String name, Map args, RACFAccessType uacc, boolean refresh) throws ZosSecurityManagerException {

		IZosImage zosimage = null;
		try {
			zosimage = getZosManager().getImage(image);
		} catch (ZosManagerException e) {
			throw new ZosSecurityManagerException("Unable to retrieve the run image", e);
		}
		IZosProfile newProfile = ZosProfileImpl.createProfile(this, zosimage, className, name, args, uacc, refresh);
		if (newProfile == null) {
			throw new ZosSecurityManagerException("Profile " + className + "/" + name + " is already in use by another run");
		}

		logger.debug("zOS Profile '" + newProfile.toString() + "' was allocated to this run");

		return (IZosProfile) newProfile;
	}

	@Override
	public void freeProfile(IZosProfile profile) throws ZosSecurityManagerException {
		try {
			((ZosProfileImpl) profile).free();
		} catch (ZosSecurityManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to free profile", e);
		}
	}

	@Override
	public void deleteProfile(IZosProfile profile) throws ZosSecurityManagerException {
		profile.delete(true);
	}

	@Override
	public void deleteProfile(IZosProfile profile, boolean refresh) throws ZosSecurityManagerException {
		profile.delete(refresh);
	}

	@Override
	public IZosKeyring createKeyring(IZosUserid userid, String label) throws ZosSecurityManagerException {
		return createKeyring(userid.getUserid(), label);
	}

	@Override
	public IZosKeyring createKeyring(String userid, String label) throws ZosSecurityManagerException {
		IZosKeyring newKeyring = ZosKeyringImpl.createKeyring(this, getZosImage(), userid, label);
		if (newKeyring == null) {
			throw new ZosSecurityManagerException("Keyring " + userid + "/" + label + " is already in use by another run");
		}

		logger.debug("zOS keyring '" + newKeyring.toString() + "' was allocated to this run");

		return newKeyring;
	}

	@Override
	public void freeKeyring(IZosKeyring keyring) throws ZosSecurityManagerException {
		try {
			((ZosKeyringImpl) keyring).free();
		} catch (ZosSecurityManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to free keyring", e);
		}
	}

	@Override
	public void deleteKeyring(IZosKeyring keyring) throws ZosSecurityManagerException {
		keyring.delete();
	}

	@Override
	public IZosCertificate createCertificate(IZosUserid userid, String label, KeyStore keyStore, String password,
			RACFCertificateType type) throws ZosSecurityManagerException {
		return createCertificate(userid.getUserid(), label, keyStore, password, type, null);
	}

	@Override
	public IZosCertificate createCertificate(String userid, String label, KeyStore keyStore, String password,
			RACFCertificateType type) throws ZosSecurityManagerException {
		return createCertificate(getZosImage().getImageID(), userid, label, keyStore,
				password, type, null);
	}

	@Override
	public IZosCertificate createCertificate(String image, IZosUserid userid, String label, KeyStore keyStore,
			String password, RACFCertificateType type) throws ZosSecurityManagerException {
		return createCertificate(image, userid.getUserid(), label, keyStore, password, type, null);
	}

	@Override
	public IZosCertificate createCertificate(String image, String userid, String label, KeyStore keyStore,
			String password, RACFCertificateType type) throws ZosSecurityManagerException {
		return createCertificate(image, userid, label, keyStore, password, type, null);
	}

	@Override
	public IZosCertificate createCertificate(IZosUserid userid, String label, KeyStore keyStore, String password,
			RACFCertificateType type, RACFCertificateTrust trust) throws ZosSecurityManagerException {
		return createCertificate(userid.getUserid(), label, keyStore, password, type, trust);
	}

	@Override
	public IZosCertificate createCertificate(String userid, String label, KeyStore keyStore, String password,
			RACFCertificateType type, RACFCertificateTrust trust) throws ZosSecurityManagerException {
		return createCertificate(getZosImage().getImageID(), userid, label, keyStore,
				password, type, trust);
	}

	@Override
	public IZosCertificate createCertificate(String image, IZosUserid userid, String label, KeyStore keyStore,
			String password, RACFCertificateType type, RACFCertificateTrust trust) throws ZosSecurityManagerException {
		return createCertificate(image, userid.getUserid(), label, keyStore, password, type, trust);
	}

	@Override
	public IZosCertificate createCertificate(String image, String userid, String label, KeyStore keyStore,
			String password, RACFCertificateType type, RACFCertificateTrust trust) throws ZosSecurityManagerException {

		IZosImage zosimage = null;
		try {
			zosimage = getZosManager().getImage(image);
		} catch (ZosManagerException e) {
			throw new ZosSecurityManagerException("Unable to retrieve the run image", e);
		}

		certificateStoreNumber++;
		IZosCertificate newCertificate = ZosCertificateImpl.createCertificate(this, zosimage, userid, label, keyStore, password, type, trust, certificateStoreNumber);
		if (newCertificate == null) {
			throw new ZosSecurityManagerException("Certificate " + userid + "/" + label + " is already in use by another run");
		}

		logger.debug("zOS Certificate '" + newCertificate.toString() + "' was allocated to this run");

		return newCertificate;

	}

	@Override
	public void freeCertificate(IZosCertificate certificate) throws ZosSecurityManagerException {
		try {
			((ZosCertificateImpl) certificate).free();
		} catch (ZosSecurityManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to free certificate", e);
		}
	}

	@Override
	public void deleteCertificate(IZosCertificate certificate) throws ZosSecurityManagerException {
		certificate.delete();
	}

	@Override
	public KeyStore generateSelfSignedCertificate(String alias, String distinguishedName,
			int keySize, int durationDays, String keyAlgorithm, String signatureAlgoritm)
					throws ZosSecurityManagerException {
		return generateSelfSignedCertificate(alias, distinguishedName, keySize, durationDays,
				keyAlgorithm, signatureAlgoritm, false);
	}

	@Override
	public KeyStore generateSelfSignedCertificate(String alias, String distinguishedName,
			int keySize, int durationDays, String keyAlgorithm, String signatureAlgoritm,
			boolean certificateAuthority) throws ZosSecurityManagerException {
		try {
			if (keyAlgorithm == null) {
				keyAlgorithm = "RSA";
			}
			if (signatureAlgoritm == null) {
				signatureAlgoritm = "SHA1withRSA";
			}

			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm);
			keyPairGenerator.initialize(keySize, new SecureRandom());
			KeyPair keyPair = keyPairGenerator.generateKeyPair();

			GregorianCalendar now = new GregorianCalendar();
			GregorianCalendar expire = new GregorianCalendar();
			expire.add(GregorianCalendar.DAY_OF_YEAR, durationDays);

			JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(signatureAlgoritm);
			ContentSigner contentSigner = contentSignerBuilder.build(keyPair.getPrivate());

			X500Name name = new X500Name(distinguishedName);

			X509v3CertificateBuilder builder =
					new JcaX509v3CertificateBuilder(name, BigInteger.valueOf(System.currentTimeMillis()),
							now.getTime(), expire.getTime(), name, keyPair.getPublic());

			builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(
					certificateAuthority));

			X509CertificateHolder holder = builder.build(contentSigner);

			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509Certificate cert =
					(X509Certificate) cf.generateCertificate(new ByteArrayInputStream(holder.getEncoded()));

			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			keyStore.load(null, null);
			keyStore.setKeyEntry(alias, keyPair.getPrivate(), "password".toCharArray(),
					new java.security.cert.Certificate[] {cert});

			logger.info("Selfsigned certificate generated with dn='" + cert.getSubjectDN().getName()
					+ "' and serial '" + cert.getSerialNumber() + "'");

			return keyStore;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to generate self signed certificate", e);
		}
	}


	@Override
	public KeyStore generateSignedCertificate(String alias, String distinguishedName, int keySize,
			int durationDays, KeyStore signingKeyStore, String signingLabel, String signingPassword)
					throws ZosSecurityManagerException {
		return generateSignedCertificate(alias, distinguishedName, keySize, durationDays,
				signingKeyStore, signingLabel, signingPassword, false);
	}

	@Override
	public KeyStore generateSignedCertificate(String alias, String distinguishedName, int keySize,
			int durationDays, KeyStore signingKeyStore, String signingLabel, String signingPassword,
			boolean certificateAuthority) throws ZosSecurityManagerException {
		try {
			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");

			Key signingKey = signingKeyStore.getKey(signingLabel, signingPassword.toCharArray());
			Certificate[] signingCerts = signingKeyStore.getCertificateChain(signingLabel);
			X509Certificate signingCertificate =
					(X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
							signingCerts[0].getEncoded()));

			String signatureAlgoritm = signingCertificate.getSigAlgName();

			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(signingKey.getAlgorithm());
			keyPairGenerator.initialize(keySize, new SecureRandom());
			KeyPair keyPair = keyPairGenerator.generateKeyPair();

			GregorianCalendar now = new GregorianCalendar();
			GregorianCalendar expire = new GregorianCalendar();
			expire.add(GregorianCalendar.DAY_OF_YEAR, durationDays);

			JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(signatureAlgoritm);
			ContentSigner contentSigner = contentSignerBuilder.build((PrivateKey) signingKey);

			X500Name name = new X500Name(distinguishedName);
			@SuppressWarnings("deprecation")
			X500Name issuer = new X500Name(PrincipalUtil.getSubjectX509Principal(signingCertificate).getName());

			X509v3CertificateBuilder builder =
					new JcaX509v3CertificateBuilder(issuer, BigInteger.valueOf(System.currentTimeMillis()),
							now.getTime(), expire.getTime(), name, keyPair.getPublic());

			builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(
					certificateAuthority));

			X509CertificateHolder holder = builder.build(contentSigner);

			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509Certificate cert =
					(X509Certificate) cf.generateCertificate(new ByteArrayInputStream(holder.getEncoded()));

			Certificate[] chain = new Certificate[1 + signingCerts.length];
			chain[0] = cert;
			int i = 1;
			for (Certificate c : signingCerts) {
				chain[i] = c;
				i++;
			}

			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			keyStore.load(null, null);
			keyStore.setKeyEntry(alias, keyPair.getPrivate(), "password".toCharArray(), chain);

			logger.info("Certificate generated with dn='" + cert.getSubjectDN().getName()
					+ "' and serial '" + cert.getSerialNumber() + "'");

			return keyStore;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to generate signed certificate", e);
		}
	}

	@Override
	public IZosIdMap createIdMap(String userid, String label, String distributedID, String registry) throws ZosSecurityManagerException {
		IZosIdMap newIdMap = ZosIdMapImpl.createIdMap(this, getZosImage(), userid, label, distributedID, registry);
		if (newIdMap == null) {
			throw new ZosSecurityManagerException("IDMap " + userid + "/" + label + " is already in use by another run");
		}

		logger.debug("zOS id map '" + newIdMap.toString() + "' was allocated to this run");

		return newIdMap;
	}

	@Override
	public IZosIdMap createIdMap(IZosUserid userid, String label, String distributedID, String registry) throws ZosSecurityManagerException {
		return createIdMap(userid.getUserid(), label, distributedID, registry);
	}

	@Override
	public void freeIdMap(IZosIdMap idmap) throws ZosSecurityManagerException {
		try {
			((ZosIdMapImpl) idmap).free();
		} catch (ZosSecurityManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to free idmap", e);
		}
	}

	@Override
	public void deleteIdMap(IZosIdMap idmap) throws ZosSecurityManagerException {
		idmap.delete();
	}

	@Override
	public IZosKerberosPrincipal createKerberosClientPrincipal(IZosKerberosPrincipal servicePrincipal, IZosUserid clientUserid) throws ZosSecurityManagerException {

		if (!image.getImageID().equals(servicePrincipal.getUserid().getZosImage().getImageID())) {
			throw new ZosSecurityManagerException("Service Principal image does not match provided image");
		}
		if (!image.getImageID().equals(clientUserid.getZosImage().getImageID())) {
			throw new ZosSecurityManagerException("Client Userid image does not match provided image");
		}

		IZosKerberosPrincipal principal = ZosKerberosClientPrincipalImpl.createPrincipal(this, servicePrincipal, clientUserid);
		if (principal == null) {
			throw new ZosSecurityManagerException("Kerberos Principal " + ZosKerberosClientPrincipalImpl.generatePrincipalName(clientUserid) + " is already in use by another run");
		}
		
		logger.debug("zOS Kerberos Client Principal '" + principal.toString() + "' was allocated to this run");

		return principal;
	}

	@Override
	public IZosKerberosPrincipal createKerberosPrincipal(IZosUserid serviceUserid, String realm) throws ZosSecurityManagerException {

		if (!image.getImageID().equals(serviceUserid.getZosImage().getImageID())) {
			throw new ZosSecurityManagerException("Userid image does not match provided image");
		}

		IZosKerberosPrincipal principal = ZosKerberosPrincipalImpl.createPrincipal(this, serviceUserid, realm);
		if (principal == null) {
			throw new ZosSecurityManagerException("Kerberos Principal " + ZosKerberosPrincipalImpl.generatePrincipalName(serviceUserid) + " is already in use by another run");
		}

		logger.debug("zOS Kerberos Principal '" + ((ZosKerberosPrincipalImpl) principal).getResourceName() + "' was allocated to this run");

		return principal;
	}

	@Override
	public void freePrincipal(IZosKerberosPrincipal principal) throws ZosSecurityManagerException {
		try {
			((ZosKerberosPrincipalImpl) principal).free();
		} catch (ZosSecurityManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new ZosSecurityManagerException("Unable to free idmap", e);
		}
	}

	@Override
	public String getDefaultKerberosRealm() throws ZosSecurityManagerException {
		return KerberosRealm.get(image);
	}

	@Override
	public String getDefaultKerberosDomainController() throws ZosSecurityManagerException {
		return KerberosDomainController.get(image);
	}

	@Override
	public KerberosToken retrieveKerberosToken(IZosKerberosPrincipal servicePrincipal,
			IZosKerberosPrincipal clientPrincipal, String kdc) throws ZosSecurityManagerException {
		KerberosInitiator initiator = createKerberosInitiator(servicePrincipal, clientPrincipal, kdc);
		initiator.create();

		return initiator.initiate();
	}

	@Override
	public KerberosInitiator createKerberosInitiator(IZosKerberosPrincipal servicePrincipal,
			IZosKerberosPrincipal clientPrincipal, String kdc) {
		return new KerberosInitiator(servicePrincipal, clientPrincipal, kdc);
	}

	@Override
	public void setRunUserid(IZosUserid user) throws ZosSecurityManagerException {
		this.runUser = user;
	}

	@Override
	public void resetRunUserid() {
		this.runUser = this.imageUser;
	}


	@Override
	public IZosImage getZosImage() throws ZosSecurityManagerException {
		return image;
	}

	@Override
	public void setResourceReporting(boolean enabled) {
		this.resourceReporting = enabled;

		if (this.resourceReporting) {
			logger.info("Resource Reporting has been enabled");
		} else {
			logger.info("Resource Reporting has been disabled");
		}
	}

	@Override
	public void setOutputReporting(boolean enabled) {
		this.outputReporting = enabled;

		if (this.outputReporting) {
			logger.info("Output Reporting has been enabled");
		} else {
			logger.info("Output Reporting has been disabled");
		}
	}

	public boolean isResourceReporting() {
		return this.resourceReporting;
	}

	public boolean isOutputReporting() {
		return this.outputReporting;
	}

	private IFramework getFramework() {
		return this.framework;
	}

	private IZosManagerSpi getZosManager() {
		return this.zosManager;
	}

	private IZosFileSpi getZosFileManager() {
		return this.zosFileManager;
	}

	private IHttpManagerSpi getHttpManager() {
		return this.httpManager;
	}

	public IHttpClient getZossecServerClient(String sysplexId) throws ZosSecurityManagerException {
		IHttpClient httpClient = zossecServerClients.get(sysplexId);

		if (httpClient != null) {
			return httpClient;
		}

		try {
			httpClient = getHttpManager().newHttpClient();
			URI uri = new URI(ServerUrl.get(sysplexId));
			httpClient.setURI(uri);
			ICredentials creds = null;
			try {
				creds = getFramework().getCredentialsService().getCredentials("w3");
			} catch (CredentialsException e) {
				throw new ZosSecurityManagerException("Problem accessing credentials store", e);
            }
            
            if (creds != null && creds instanceof ICredentialsUsernamePassword) {
                httpClient.setAuthorisation(((ICredentialsUsernamePassword) creds).getUsername(), ((ICredentialsUsernamePassword) creds).getPassword());
            } else {
            	throw new ZosSecurityManagerException("Unable to get w3 credentials");
            }
			String apikey = ServerApikey.get();
			httpClient.addCommonHeader("ejat-zossec-apikey", apikey);
			httpClient.addOkResponseCode(500);
			httpClient.addOkResponseCode(415);
			if (uri.getScheme().equals("https")) {
				httpClient.setTrustingSSLContext();
			}

			zossecServerClients.put(sysplexId, httpClient);
		} catch(Exception e) {
			throw new ZosSecurityManagerException("Unable to create zossec server client for " + image.getSysplexID(), e);
		}

		return httpClient;
	}

	public void addClassToBeRefreshed(String sysplexId, String className) {
		synchronized (classesRequiringRefresh) {

			HashSet sysplexClasses = classesRequiringRefresh.get(sysplexId);

			if (sysplexClasses == null) {
				sysplexClasses = new HashSet();
				classesRequiringRefresh.put(sysplexId, sysplexClasses);
			}			

			sysplexClasses.add(className);
		}
	}

	public void refreshClasses(String sysplexId) throws ZosSecurityManagerException {
		HashSet sysplexClasses = null;
		synchronized (classesRequiringRefresh) {
			sysplexClasses = classesRequiringRefresh.remove(sysplexId);
		}

		if (sysplexClasses == null || sysplexClasses.isEmpty()) {
			logger.debug("No classes required to be refreshed on " + image.getSysplexID() + ", ignoring");
		}

		logger.info("Requesting SETROPTS refresh of " + sysplexClasses);

		try {
			JsonObject jsonBody = new JsonObject();
			JsonArray jsonClasses = new JsonArray();
			for(String c : sysplexClasses) {
				jsonClasses.add(c);
			}
			jsonBody.add("classes", jsonClasses);

			long start = System.currentTimeMillis();
			JsonObject response = clientRequest(sysplexId, HttpMethod.PUT, "/api/refresh", zosSecurityServerQueryParams, jsonBody);
			long end = System.currentTimeMillis();
			RacfOutputProcessing.analyseOutput(response, RacfOutputProcessing.COMMAND.REFRESH, sysplexClasses.toString(), isOutputReporting());

			logger.debug("SETROPTS command took " + (end - start) + "ms to action, includes mandatory " + setroptsDelay + "ms wait");
		} catch (ZosSecurityManagerException e) {
			throw new ZosSecurityManagerException("REFRESH of " + sysplexClasses.toString() + " failed", e);
		}
	}

	public void dssRegister(String resourceType, String resourceName) throws ZosSecurityManagerException {
		try {
			String sysplexId = getZosImage().getSysplexID();
			String allocated = Instant.now().toString();
			String runName = getRunName();
			
			HashMap props = new HashMap<>();
			props.put(resourceType + "." + resourceName + ".sysplex." + sysplexId + ".run", runName);
			props.put(resourceType + ".run." + runName + "." + resourceName +".sysplex." + sysplexId, "active");
			this.dss.put(props);
	
			props = new HashMap<>();
			props.put(resourceName + ".sysplex." + sysplexId + ".run", runName);
			props.put(resourceName + ".sysplex." + sysplexId + ".run." + runName + ".allocated", allocated);
			getDynamicResource(resourceType).put(props);
		} catch (DynamicStatusStoreException e) {
			throw new ZosSecurityManagerException("Problem setting slot for zOS " + resourceType + " " + resourceName, e);
		}
	}
		
	public void dssUnregister(String resourceType, String resourceName, String sysplexId, String runName) throws ZosSecurityManagerException {
		try {
			HashSet props = new HashSet<>();
			props.add(resourceName + ".sysplex." + sysplexId + ".run");
			props.add(resourceName + ".sysplex." + sysplexId + ".run." + runName + ".allocated");
			getDynamicResource(resourceType).delete(props);
			
			props = new HashSet<>();
			props.add(resourceType + "." + resourceName + ".sysplex." + sysplexId + ".run");
			props.add(resourceType + ".run." + runName + "." + resourceName +".sysplex." + sysplexId);
			this.dss.delete(props);
		} catch (DynamicStatusStoreException e) {
			throw new ZosSecurityManagerException("Problem removing slot for zOS " + resourceType + " " + resourceName, e);
		}
	}

	public void dssFree(String resourceType, String resourceName) throws ZosSecurityManagerException {
		try {
			String sysplexId = getZosImage().getSysplexID();
			String runName = getRunName();
			this.dss.put(resourceType + ".run." + runName + "." + resourceName +".sysplex." + sysplexId, "free");
		} catch (DynamicStatusStoreException e) {
			throw new ZosSecurityManagerException("Problem updating slot for zOS " + resourceType + " " + resourceName, e);
		}
	}

	private IDynamicStatusStoreKeyAccess getDynamicResource(String resourceType) {
		return this.dss.getDynamicResource(resourceType);
	}

	public String getRunName() {
		return this.framework.getTestRunName();
	}	
	
	public JsonObject clientRequest(String sysplexId, HttpMethod method, String path, Map queryParams, JsonObject body) throws ZosSecurityManagerException {
		if (body == null) {
			body = new JsonObject();
		}
		IHttpClient client = getZossecServerClient(sysplexId);
		HttpClientResponse response;
		try {
			switch (method) {
			case GET:
				response = client.getJson(buildUri(path, queryParams));
				break;
			case PUT:
				response = client.putJson(buildUri(path, queryParams), body);
				break;
			case POST:
				response = client.postJson(buildUri(path, queryParams), body);
				break;
			case DELETE:
				response = client.deleteJson(buildUri(path, queryParams));
				break;
			default:
				throw new ZosSecurityManagerException("Invalid HTTP method \"" + method + "\"");
			}
		} catch (HttpClientException e) {
			throw new ZosSecurityManagerException("Server request failed", e);
		}
		return response.getContent();
	}

	private String buildUri(String path, Map queryParams) {
		if (queryParams.isEmpty()) {
			return path;
		}
		StringBuilder sb = new StringBuilder();
		sb.append(path);
		sb.append("?");
		for (Entry entry: queryParams.entrySet()) {
			if (!sb.toString().endsWith("?")) {
				sb.append("&");
			}
			sb.append(entry.getKey());
			sb.append("=");
			sb.append(entry.getValue());
		}
		return sb.toString();
	}
	
	@Override
	public String toString() {
		return "[zOS Security] " + this.image;
	}

	public IZosFileHandler getZosFileHandler() throws ZosSecurityManagerException {
		if (this.zosFileHandler == null) {
			try {
				this.zosFileHandler = getZosFileManager().getZosFileHandler();
			} catch (ZosFileManagerException e) {
				throw new ZosSecurityManagerException("Unable to get zOS File Handler", e); 
			}
		}
		return this.zosFileHandler;
			
	}

	public String getRunDatasetHLQ(IZosImage image) throws ZosSecurityManagerException {
		if (this.runDatasetHLQ == null) {
			try {
				this.runDatasetHLQ = getZosManager().getRunDatasetHLQ(image);
			} catch (ZosManagerException e) {
				throw new ZosSecurityManagerException("Unable to get Run Dataset HLQ", e);
			}
		}
		return this.runDatasetHLQ;
	}

	public List getUseridPool() {
		return this.useridPool;
	}

	public String getUseridFromPool(boolean createUserid) throws ZosSecurityManagerException {
		String sysplexId = getZosImage().getSysplexID();
		String resourceType = ResourceType.ZOS_USERID.getName();
		for (String userName: this.useridPool) {
			
			Map allocatedUserids;
			try {
				allocatedUserids = this.dss.getPrefix(resourceType + "." + userName + ".sysplex." + sysplexId + ".run");
			} catch (DynamicStatusStoreException e) {
				throw new ZosSecurityManagerException("Problem getting userid from pool for image " + getZosImage(), e);
			}
			if (allocatedUserids.isEmpty()) {
				dssRegister(resourceType, userName);
				return userName;
			}
		}
		throw new ZosSecurityManagerException("No Userids available in pool for image " + getZosImage());
	}
	
	public String getCicsClassSetFromPool() throws ZosSecurityManagerException {
		String sysplexId = getZosImage().getSysplexID();
		String resourceType = ResourceType.ZOS_CICS_CLASS_SET.getName();
		for (String ClassSetName: this.cicsSharedClassSets) {
			
			Map allocatedClassSets;
			try {
				allocatedClassSets = this.dss.getPrefix(resourceType + "." + ClassSetName + ".sysplex." + sysplexId + ".run");
			} catch (DynamicStatusStoreException e) {
				throw new ZosSecurityManagerException("Problem getting CICS Class Set from pool for image " + getZosImage(), e);
			}
			if (allocatedClassSets.isEmpty()) {
				dssRegister(resourceType, ClassSetName);
				return ClassSetName;
			}
		}
		throw new ZosSecurityManagerException("No CICS Class Sets available in pool for image " + getZosImage());
	}

	public boolean createUserid() {
		return createUserid;
	}

	public String getUseridDefaultGroup() throws ZosSecurityManagerException {
		if (useridDefaultGroup == null) {
			useridDefaultGroup = UseridDefaultGroup.get();
		}
		return useridDefaultGroup;
	}

	public List getUseridGroups() throws ZosSecurityManagerException {
		if (useridDefaultGroups == null) {
			useridDefaultGroups = UseridDefaultGroups.get();
		}
		return useridDefaultGroups;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy