/nssdb/
/*.pem
/old/
+/rootCA/
emailAddress = optional
[ req ]
-default_bits = 1024
+default_bits = 4096
default_md = sha1
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
x509_extensions = v3_ca # The extensions to add to the self signed cert
# Passwords for private keys if not present they will be prompted for
-# input_password = secret
-# output_password = secret
+input_password = demo
+output_password = demo
string_mask = utf8only
req_extensions = v3_req # The extensions to add to a certificate request
#stateOrProvinceName = State or Province Name (full name)
#localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
-#organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, your name or your server\'s hostname)
commonName_max = 64
emailAddress = Email Address
#stateOrProvinceName_default = Berlin
#localityName_default = Berlin
0.organizationName_default = Example
-#organizationalUnitName_default = Certificate Authorities
-commonName_default = Certificate Authority
+organizationalUnitName_default = Certificate Authorities
+commonName_default = Intermediate CA
[ req_attributes ]
#challengePassword = A challenge password
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
-basicConstraints = critical,CA:true
-# keyUsage = cRLSign, keyCertSign
-
-#subjectAltName=email:copy
-issuerAltName=issuer:copy
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ crl_ext ]
issuerAltName=issuer:copy
--- /dev/null
+dir = ./rootCA # Where everything is kept
+
+[ ca ]
+default_ca = CA_default # The default ca section
+
+[ CA_default ]
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+new_certs_dir = $dir/newcerts # default place for new certs.
+certificate = $dir/cacert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crlnumber = $dir/crlnumber # the current crl number
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/private/cakey.pem # The private key
+x509_extensions = usr_cert # The extentions to add to the cert
+name_opt = ca_default # Subject Name options
+cert_opt = ca_default # Certificate field options
+crl_extensions = crl_ext
+default_days = 3650 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = default # use public key default MD
+preserve = no # keep passed DN ordering
+policy = policy_match
+
+[ policy_match ]
+countryName = optional
+stateOrProvinceName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = optional
+emailAddress = optional
+
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = optional
+emailAddress = optional
+
+[ req ]
+default_bits = 4096
+default_md = sha1
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extensions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+input_password = demo
+output_password = demo
+
+string_mask = utf8only
+req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_min = 2
+countryName_max = 2
+#stateOrProvinceName = State or Province Name (full name)
+#localityName = Locality Name (eg, city)
+0.organizationName = Organization Name (eg, company)
+organizationalUnitName = Organizational Unit Name (eg, section)
+commonName = Common Name (eg, your name or your server\'s hostname)
+commonName_max = 64
+emailAddress = Email Address
+emailAddress_max = 64
+# SET-ex3 = SET extension number 3
+
+##
+## DEFAULT VALUES
+##
+countryName_default = DE
+#stateOrProvinceName_default = Berlin
+#localityName_default = Berlin
+0.organizationName_default = Example
+organizationalUnitName_default = Certificate Authorities
+commonName_default = Root CA
+
+[ req_attributes ]
+#challengePassword = A challenge password
+#challengePassword_min = 4
+#challengePassword_max = 20
+#unstructuredName = An optional company name
+
+[ usr_cert ]
+basicConstraints=CA:FALSE
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+subjectAltName=email:move
+issuerAltName=issuer:copy
+
+[ v3_req ]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ crl_ext ]
+issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always
+
+[ server_ext ]
+extendedKeyUsage=serverAuth
+
+[ user_ext ]
+extendedKeyUsage=clientAuth,emailProtection
# all *.p12 passwords are 'demo'
# all *.jks passwords are 'changeit'
+INTERMEDIATE_CA_DN="/C=DE/O=Example/OU=Certificate Authorities/CN=Intermediate CA/"
SERVER_DN=/C=DE/O=Example/OU=Systems/CN=$HOSTNAME/
-USERS_BASE_DN=/DC=com/DC=example/OU=users
-
-export OPENSSL_CONF=./openssl.cnf
-export CATOP=./CA
+USERS_BASE_DN=/DC=com/DC=example/OU=People
+echo ## Init directory structure
+# Root
+export OPENSSL_CONF=./openssl_root.cnf
+export CATOP=./rootCA
/etc/pki/tls/misc/CA -newca
+# Intermediate
+mkdir -p ./CA/{certs,crl,csr,newcerts,private}
-#openssl req -x509 -new -newkey rsa:4096 -extensions server_ext -days 365 \
-# -subj $SERVER_DN \
-# -keyout newkey.pem -passout pass:demo -out newcrt.pem
-
-# Self-signed server certificate
-#openssl pkcs12 -export -passin pass:demo -passout pass:changeit \
-# -name "jetty" -inkey newkey.pem -in newcrt.pem \
-# -certfile ./CA/cacert.pem \
-# -out server.p12
-
- # Convert PKCS12 keystore into a JKS keystore
-#keytool -importkeystore \
-# -srckeystore server.p12 -srcstoretype pkcs12 -srcstorepass changeit \
-# -alias jetty -destkeystore server.jks -deststorepass changeit
-#rm -f server.p12
+echo ## Create intermediate certificate
+openssl req -new -newkey rsa:4096 -extensions v3_intermediate_ca \
+ -subj "$INTERMEDIATE_CA_DN" \
+ -keyout ./CA/private/cakey.pem -passout pass:demo -out ica_csr.pem
+openssl ca -batch -passin pass:demo -in ica_csr.pem -out ./CA/cacert.pem
+
+# create index and serial
+touch ./CA/index.txt
+# (below is from openssl CA script)
+openssl x509 -in ./CA/cacert.pem -noout -next_serial -out ./CA/serial
-# Import People CA
-#keytool -importcert -keystore server.jks -storepass changeit \
-# -alias CA -file CA/cacert.pem
+# Switch to intermediate CA
+export OPENSSL_CONF=./openssl.cnf
+export CATOP=./CA
-openssl req -new -newkey rsa:4096 -extensions server_ext -days 365 \
+echo ## Create server key and certificate
+openssl req -new -newkey rsa:4096 -extensions server_ext \
-subj $SERVER_DN \
-keyout node_key.pem -passout pass:demo -out node_csr.pem
openssl ca -batch -passin pass:demo -in node_csr.pem -out node_crt.pem
-cat node_crt.pem CA/cacert.pem > node.pem
-openssl pkcs12 -export -passin pass:demo -passout pass:demo \
- -name "node" -inkey node_key.pem -in node.pem \
+cat node_crt.pem ./CA/cacert.pem ./rootCA/cacert.pem > chain.pem
+openssl pkcs12 -export -passin pass:demo -passout pass:changeit \
+ -name "$HOSTNAME" -inkey node_key.pem -in chain.pem \
-out node.p12
+echo ## Import Certificate Authority into keystore
+keytool -importcert -noprompt -keystore node.p12 -storepass changeit \
+ -alias "rootCA" -file ./rootCA/cacert.pem
+keytool -importcert -noprompt -keystore node.p12 -storepass changeit \
+ -alias "CA" -file ./CA/cacert.pem
+cp node.p12 ../init/node/
-# root user
-openssl req -new -newkey rsa:4096 -extensions user_ext -days 365 \
+echo ## Create 'root' user client certificate
+openssl req -new -newkey rsa:4096 -extensions user_ext \
-subj $USERS_BASE_DN/UID=root/ \
-keyout newkey.pem -passout pass:demo -out newcsr.pem
openssl ca -preserveDN -batch -passin pass:demo -in newcsr.pem -out newcrt.pem
+cat newcrt.pem ./CA/cacert.pem ./rootCA/cacert.pem > newchain.pem
openssl pkcs12 -export -passin pass:demo -passout pass:demo \
- -name "root" -inkey newkey.pem -in newcrt.pem \
+ -name "root" -inkey newkey.pem -in newchain.pem \
-out root.p12
# demo user
# -name "demo" -inkey newkey.pem -in newcrt.pem \
# -out demo.p12
-# Clean up
-#rm -vf new*.pem
+# Self-signed
+#openssl req -x509 -new -newkey rsa:4096 -extensions server_ext -days 365 \
+# -subj $SERVER_DN \
+# -keyout newkey.pem -passout pass:demo -out newcrt.pem
+# Self-signed server certificate
+#openssl pkcs12 -export -passin pass:demo -passout pass:changeit \
+# -name "jetty" -inkey newkey.pem -in newcrt.pem \
+# -certfile ./CA/cacert.pem \
+# -out server.p12
+
+echo ## Clean up
+rm -vf *.pem
final static String SHARED_STATE_HTTP_REQUEST = "org.argeo.cms.auth.http.request";
final static String SHARED_STATE_SPNEGO_TOKEN = "org.argeo.cms.auth.spnegoToken";
final static String SHARED_STATE_SPNEGO_OUT_TOKEN = "org.argeo.cms.auth.spnegoOutToken";
+ final static String SHARED_STATE_CERTIFICATE_CHAIN = "org.argeo.cms.auth.certificateChain";
static void addAuthorization(Subject subject, Authorization authorization, Locale locale,
HttpServletRequest request) {
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
-import org.argeo.naming.LdapAttrs;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
}
// auth token
-// String mail = request.getParameter(LdapAttrs.mail.name());
-// String authPassword = request.getParameter(LdapAttrs.authPassword.name());
-// if (authPassword != null) {
-// sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, authPassword);
-// if (mail != null)
-// sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, mail);
-// }
+ // String mail = request.getParameter(LdapAttrs.mail.name());
+ // String authPassword = request.getParameter(LdapAttrs.authPassword.name());
+ // if (authPassword != null) {
+ // sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, authPassword);
+ // if (mail != null)
+ // sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, mail);
+ // }
}
- private X509Certificate[] extractClientCertificate(HttpServletRequest req) {
+ private void extractClientCertificate(HttpServletRequest req) {
X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
if (null != certs && certs.length > 0) {
- return certs;
+ sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, certs[0].getSubjectX500Principal().getName());
+ sharedState.put(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN, certs);
}
- return null;
}
}
import java.io.IOException;
import java.security.PrivilegedAction;
+import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
final String username;
final char[] password;
+ X509Certificate[] certificateChain = null;
if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME)
&& sharedState.containsKey(CmsAuthUtils.SHARED_STATE_PWD)) {
// NB: required by Basic http auth
username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
password = (char[]) sharedState.get(CmsAuthUtils.SHARED_STATE_PWD);
// // TODO locale?
+ } else if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME)
+ && sharedState.containsKey(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN)) {
+ // NB: required by Basic http auth
+ username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
+ certificateChain = (X509Certificate[]) sharedState.get(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN);
+ password = null;
} else {
// ask for username and password
NameCallback nameCallback = new NameCallback("User");
if (locale == null)
locale = Locale.getDefault();
// FIXME add it to Subject
-// Locale.setDefault(locale);
+ // Locale.setDefault(locale);
username = nameCallback.getName();
if (username == null || username.trim().equals("")) {
else
throw new CredentialNotFoundException("No credentials provided");
}
-
User user = searchForUser(userAdmin, username);
if (user == null)
return true;// expect Kerberos
-
- // try bind first
- try {
- AuthenticatingUser authenticatingUser = new AuthenticatingUser(user.getName(), password);
- bindAuthorization = userAdmin.getAuthorization(authenticatingUser);
- // TODO check tokens as well
- if (bindAuthorization != null) {
- authenticatedUser = user;
- return true;
+
+ if (password != null) {
+ // try bind first
+ try {
+ AuthenticatingUser authenticatingUser = new AuthenticatingUser(user.getName(), password);
+ bindAuthorization = userAdmin.getAuthorization(authenticatingUser);
+ // TODO check tokens as well
+ if (bindAuthorization != null) {
+ authenticatedUser = user;
+ return true;
+ }
+ } catch (Exception e) {
+ // silent
+ if (log.isTraceEnabled())
+ log.trace("Bind failed", e);
}
- } catch (Exception e) {
- // silent
- if(log.isTraceEnabled())
- log.trace("Bind failed", e);
- }
-
- // works only if a connection password is provided
- if (!user.hasCredential(null, password)) {
- return false;
+
+ // works only if a connection password is provided
+ if (!user.hasCredential(null, password)) {
+ return false;
+ }
+ } else if (certificateChain != null) {
+ // TODO check CRLs/OSCP validity?
+ // NB: authorization in commit() will work only if an LDAP connection password is provided
+ }else {
+ throw new CredentialNotFoundException("No credentials provided");
}
+
authenticatedUser = user;
return true;
}
public static KeyStore getKeyStore(File keyStoreFile, char[] keyStorePassword) {
try {
- KeyStore store = KeyStore.getInstance("PKCS12", SECURITY_PROVIDER);
+ KeyStore store = KeyStore.getInstance("JKS", SECURITY_PROVIDER);
if (keyStoreFile.exists()) {
try (FileInputStream fis = new FileInputStream(keyStoreFile)) {
store.load(fis, keyStorePassword);