Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.summerboot.jexpress.security.auth.AuthConfig Maven / Gradle / Ivy
/*
* Copyright 2005-2022 Du Law Office - The Summer Boot Framework Project
*
* The Summer Boot Project licenses this file to you under the Apache License, version 2.0 (the
* "License"); you may not use this file except in compliance with the License and you have no
* policy prohibiting employee contributions back to this file (unless the contributor to this
* file is your current or retired employee). You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.summerboot.jexpress.security.auth;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import org.bouncycastle.operator.OperatorCreationException;
import org.summerboot.jexpress.boot.BootConstant;
import org.summerboot.jexpress.boot.config.BootConfig;
import org.summerboot.jexpress.boot.config.ConfigUtil;
import org.summerboot.jexpress.boot.config.annotation.Config;
import org.summerboot.jexpress.boot.config.annotation.ConfigHeader;
import org.summerboot.jexpress.integration.ldap.LdapAgent;
import org.summerboot.jexpress.integration.ldap.LdapSSLConnectionFactory1;
import org.summerboot.jexpress.security.EncryptorUtil;
import org.summerboot.jexpress.security.JwtUtil;
import javax.crypto.SecretKey;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
/**
* @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
*/
//@ImportResource(BootConstant.FILE_CFG_AUTH)
public class AuthConfig extends BootConfig {
public static void main(String[] args) {
String t = generateTemplate(AuthConfig.class);
System.out.println(t);
}
public static final AuthConfig cfg = new AuthConfig();
protected AuthConfig() {
}
@Override
public AuthConfig temp() {
AuthConfig temp = (AuthConfig) super.temp();
AuthConfig current = cfg;//AuthConfig.instance(AuthConfig.class);
temp.addDeclareRoles(current.getDeclareRoles());
return temp;
}
@Override
public void shutdown() {
}
//1.1 LDAP settings
@ConfigHeader(title = "1.1 LDAP connection settings")
@Config(key = "ldap.type.AD",
desc = "set it true only when LDAP is implemented by Microsoft Active Directory (AD)\n"
+ "false when use others like Open LDAP, IBM Tivoli, Apache")
protected volatile boolean typeAD = false;
@Config(key = "ldap.host",
desc = "LDAP will be disabled when host is not provided")
protected volatile String ldapHost;
@Config(key = "ldap.port",
desc = "LDAP 389, LDAP over SSL 636, AD global 3268, AD global voer SSL 3269")
protected volatile int ldapPort;
@Config(key = "ldap.baseDN")
protected volatile String ldapBaseDN;
@Config(key = "ldap.bindingUserDN")
protected volatile String bindingUserDN;
@JsonIgnore
@Config(key = "ldap.bindingPassword", validate = Config.Validate.Encrypted)
protected volatile String bindingPassword;
@Config(key = "ldap.PasswordAlgorithm", defaultValue = "SHA3-256")
protected volatile String passwordAlgorithm = "SHA3-256";
@Config(key = "ldap.schema.TenantGroup.ou")
protected volatile String ldapScheamTenantGroupOU;
//1.2 LDAP Client keystore
@ConfigHeader(title = "1.2 LDAP Client keystore")
@JsonIgnore
@Config(key = "ldap.ssl.KeyStore", StorePwdKey = "ldap.ssl.KeyStorePwd",
AliasKey = "ldap.ssl.KeyAlias", AliasPwdKey = "ldap.ssl.KeyPwd",
desc = DESC_KMF)
protected volatile KeyManagerFactory kmf;
@Config(key = "ldap.ssl.protocol")
protected volatile String ldapTLSProtocol = "TLSv1.3";
@Config(key = "ldap.SSLConnectionFactoryClass")
protected volatile String ldapSSLConnectionFactoryClassName = LdapSSLConnectionFactory1.class.getName();
//1.3 LDAP Client truststore
@ConfigHeader(title = "1.3 LDAP Client truststore")
@Config(key = "ldap.ssl.TrustStore", StorePwdKey = "ldap.ssl.TrustStorePwd",
desc = DESC_TMF)
@JsonIgnore
protected volatile TrustManagerFactory tmf;
protected volatile Properties ldapConfig;
//2. JWT
protected static final String KEY_privateKeyFile = "jwt.asymmetric.SigningKeyFile";
protected static final String KEY_privateKeyPwd = "jwt.asymmetric.SigningKeyPwd";
protected static final String KEY_publicKeyFile = "jwt.asymmetric.ParsingKeyFile";
protected static final String JWT_PRIVATE_KEY_FILE = "jwt_private.key";
protected static final String JWT_PUBLIC_KEY_FILE = "jwt_public.key";
@ConfigHeader(title = "2. JWT",
example = "To generate the keypair manually:\n"
+ "step1. generate keypair: openssl genrsa -des3 -out keypair.pem 4096 \n"
+ "step2. export public key: openssl rsa -in keypair.pem -outform PEM -pubout -out " + JWT_PUBLIC_KEY_FILE + " \n"
+ "step3. export private key: openssl rsa -in keypair.pem -out private_unencrypted.pem -outform PEM \n"
+ "step4. encrypt and convert private key from PKCS#1 to PKCS#8: openssl pkcs8 -topk8 -inform PEM -outform PEM -in private_unencrypted.pem -out " + JWT_PRIVATE_KEY_FILE)
@Config(key = KEY_privateKeyFile,
desc = "Path to an encrypted RSA private key file in PKCS#8 format with minimal 2048 key size",
callbackMethodName4Dump = "generateTemplate_privateKeyFile")
protected volatile File privateKeyFile;
protected void generateTemplate_privateKeyFile(StringBuilder sb) {
sb.append(KEY_privateKeyFile + "=" + JWT_PRIVATE_KEY_FILE + "\n");
generateTemplate = true;
}
@JsonIgnore
@Config(key = KEY_privateKeyPwd, validate = Config.Validate.Encrypted,
desc = "The password of this private key",
callbackMethodName4Dump = "generateTemplate_privateKeyPwd")
protected volatile String privateKeyPwd;
protected void generateTemplate_privateKeyPwd(StringBuilder sb) {
sb.append(KEY_privateKeyPwd + "=DEC(" + BootConstant.DEFAULT_ADMIN_MM + ")\n");
}
@Config(key = KEY_publicKeyFile,
desc = "Path to the public key file corresponding to this private key",
callbackMethodName4Dump = "generateTemplate_publicKeyFile")
protected volatile File publicKeyFile;
protected void generateTemplate_publicKeyFile(StringBuilder sb) {
sb.append(KEY_publicKeyFile + "=" + JWT_PUBLIC_KEY_FILE + "\n");
}
@JsonIgnore
@Config(key = "jwt.symmetric.key", validate = Config.Validate.Encrypted,
desc = "HMAC-SHA key for bothe signing and parsing, it will be ignored when asymmetric one is specified.\n"
+ "Use this command to generate this key: java -jar .jar -jwt ")
protected volatile String symmetricKey;
@JsonIgnore
protected volatile Key jwtSigningKey;
@JsonIgnore
protected volatile JwtParser jwtParser;
@Config(key = "jwt.ttl.minutes")
protected volatile int jwtTTLMinutes = 1440;
@Config(key = "jwt.issuer")
protected volatile String jwtIssuer;
//3. Role mapping
@ConfigHeader(title = "3. Role mapping",
desc = "Map the role (defined as @RolesAllowed({\"AppAdmin\"})) with user group (no matter the group is defined in LDAP or DB)",
format = "roles..groups=csv list of groups\n"
+ "roles..users=csv list of users",
example = "the following example maps one group(AppAdmin_Group) and two users(johndoe, janejoe) to a role(AppAdmin)\n"
+ "roles.AppAdmin.groups=AppAdmin_Group\n"
+ "roles.AppAdmin.users=johndoe, janejoe",
callbackMethodName4Dump = "generateTemplate_DumpRoleMapping")
protected Map roles = new HashMap();
/**
* called by @ConfigHeader.callbackMethodName4Dump value
*
* @param sb
*/
protected void generateTemplate_DumpRoleMapping(StringBuilder sb) {
for (String role : declareRoles) {
sb.append("roles.").append(role).append(".groups=\n");
sb.append("#roles.").append(role).append(".users=\n");
}
}
@Override
protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil helper, Properties props) throws IOException, OperatorCreationException, GeneralSecurityException {
// 1. LDAP Client keystore
if (ldapHost != null) {
// 1.1 LDAP Client keystore
boolean isSSLEnabled = kmf != null;
if (isSSLEnabled) {
//LdapSSLConnectionFactory1.init(kmf == null ? null : kmf.getKeyManagers(), tmf == null ? null : tmf.getTrustManagers(), ldapTLSProtocol);
//ldapSSLConnectionFactoryClassName = LdapSSLConnectionFactory1.class.getName();
String key = "ldap.SSLConnectionFactoryClass";
try {
Class> sslFactoryClass = Class.forName(ldapSSLConnectionFactoryClassName);
Method method = sslFactoryClass.getMethod("init", KeyManagerFactory.class, TrustManagerFactory.class, String.class);
method.invoke(null, kmf, tmf, ldapTLSProtocol);
} catch (ClassNotFoundException ex) {
helper.addError("invalid \"" + key + ", error=" + ex);
} catch (NoSuchMethodException ex) {
helper.addError("invalid \"" + key + "missing method: public static void init(KeyManagerFactory kmf, TrustManagerFactory tmf, String protocol), error=" + ex);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
helper.addError("invalid \"" + key + "failed to invoke method: public static void init(KeyManagerFactory kmf, TrustManagerFactory tmf, String protocol), error=" + ex);
}
}
//1.2 LDAP info
ldapConfig = LdapAgent.buildCfg(ldapHost, ldapPort, isSSLEnabled, ldapSSLConnectionFactoryClassName, ldapTLSProtocol, bindingUserDN, bindingPassword);
}
// 2. JWT
if (symmetricKey != null) {
//jwtSigningKey = EncryptorUtil.keyFromString(jwtSigningKeyString, jwtSignatureAlgorithm.getJcaName());
jwtSigningKey = JwtUtil.parseSigningKey(symmetricKey);
jwtParser = Jwts.parser() // (1)
.verifyWith((SecretKey) jwtSigningKey) // (2)
.build(); // (3)
}
//File rootFolder = cfgFile.getParentFile().getParentFile();
if (privateKeyFile != null) {
createIfNotExist(JWT_PRIVATE_KEY_FILE, JWT_PRIVATE_KEY_FILE);
jwtSigningKey = EncryptorUtil.loadPrivateKey(privateKeyFile, privateKeyPwd.toCharArray());
}
if (publicKeyFile != null) {
createIfNotExist(JWT_PUBLIC_KEY_FILE, JWT_PUBLIC_KEY_FILE);
PublicKey publicKey = EncryptorUtil.loadPublicKey(EncryptorUtil.KeyFileType.PKCS12, publicKeyFile);
jwtParser = Jwts.parser() // (1)
.verifyWith(publicKey) // (2)
.build(); // (3)
}
// 3. Cache TTL
//jwtTTL = TimeUnit.MINUTES.toMillis(jwtTTLMinutes);
//userTTL = TimeUnit.MINUTES.toMillis(userTTL);
// 4. Role mapping
Set keys = props.keySet();
Map rolesTemp = new HashMap();
keys.forEach((key) -> {
String name = key.toString();
if (name.startsWith("roles.")) {
String[] names = name.split("\\.");
String roleName = names[1];
if (!declareRoles.contains(roleName)) {
helper.addError("Undefined role: (\"" + roleName + "\") is not defined in any @Controller @RolesAllowed(" + declareRoles + ") - line: " + key + "=" + props.getProperty(key.toString()));
}
RoleMapping.Type type = RoleMapping.Type.valueOf(names[2]);
RoleMapping rm = rolesTemp.get(roleName);
if (rm == null) {
rm = new RoleMapping(roleName);
rolesTemp.put(roleName, rm);
}
rm.add(type, props.getProperty(key.toString()));
}
});
roles = Map.copyOf(rolesTemp);
String error = helper.getError();
if (error != null) {
throw new IllegalArgumentException(error);
}
}
public String getLdapHost() {
return ldapHost;
}
public int getLdapPort() {
return ldapPort;
}
public String getLdapBaseDN() {
return ldapBaseDN;
}
public String getBindingUserDN() {
return bindingUserDN;
}
public String getLdapScheamTenantGroupOU() {
return ldapScheamTenantGroupOU;
}
public String getPasswordAlgorithm() {
return passwordAlgorithm;
}
public void setPasswordAlgorithm(String passwordAlgorithm) {
this.passwordAlgorithm = passwordAlgorithm;
}
public String getLdapSSLConnectionFactoryClassName() {
return ldapSSLConnectionFactoryClassName;
}
public String getLdapTLSProtocol() {
return ldapTLSProtocol;
}
public boolean isTypeAD() {
return typeAD;
}
@JsonIgnore
public Properties getLdapConfig() {
return ldapConfig;
}
@JsonIgnore
public Key getJwtSigningKey() {
return jwtSigningKey;
}
@JsonIgnore
public JwtParser getJwtParser() {
return jwtParser;
}
public String getJwtIssuer() {
return jwtIssuer;
}
public int getJwtTTLMinutes() {
return jwtTTLMinutes;
}
public RoleMapping getRole(String role) {
return roles.get(role);
}
public Map getRoles() {
return roles;
}
@JsonIgnore
public String getBindingPassword() {
return bindingPassword;
}
@JsonIgnore
public KeyManagerFactory getKmf() {
return kmf;
}
@JsonIgnore
public TrustManagerFactory getTmf() {
return tmf;
}
@JsonIgnore
public File getPrivateKeyFile() {
return privateKeyFile;
}
@JsonIgnore
public String getPrivateKeyPwd() {
return privateKeyPwd;
}
@JsonIgnore
public File getPublicKeyFile() {
return publicKeyFile;
}
@JsonIgnore
public String getSymmetricKey() {
return symmetricKey;
}
//@Deprecated - should use annotation jakarta.annotation.security.DeclareRoles
// public Set getRoleNames() {
// return Set.copyOf(roles.keySet());
// }
protected final Set declareRoles = new TreeSet();
public void addDeclareRoles(Set scanedDeclareRoles) {
this.declareRoles.addAll(Set.copyOf(scanedDeclareRoles));
}
public Set getDeclareRoles() {
return Set.copyOf(declareRoles);
}
}