]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java
Re-add org.argeo.cms.util.useradmin
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / kernel / NodeSecurity.java
1 package org.argeo.cms.internal.kernel;
2
3 import static org.argeo.cms.internal.kernel.KernelUtils.getOsgiInstanceDir;
4
5 import java.io.File;
6 import java.io.IOException;
7 import java.net.URL;
8 import java.security.KeyStore;
9 import java.util.Arrays;
10
11 import javax.security.auth.Subject;
12 import javax.security.auth.callback.Callback;
13 import javax.security.auth.callback.CallbackHandler;
14 import javax.security.auth.callback.NameCallback;
15 import javax.security.auth.callback.PasswordCallback;
16 import javax.security.auth.callback.UnsupportedCallbackException;
17 import javax.security.auth.login.LoginContext;
18 import javax.security.auth.login.LoginException;
19 import javax.security.auth.x500.X500Principal;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.argeo.cms.CmsException;
24 import org.argeo.cms.auth.AuthConstants;
25
26 /** Low-level kernel security */
27 class NodeSecurity implements KernelConstants {
28 private final static Log log = LogFactory.getLog(NodeSecurity.class);
29
30 public final static int HARDENED = 3;
31 public final static int STAGING = 2;
32 public final static int DEV = 1;
33
34 private final boolean firstInit;
35
36 private final Subject kernelSubject;
37 private int securityLevel = STAGING;
38
39 private final File keyStoreFile;
40
41 public NodeSecurity() {
42 // Configure JAAS first
43 URL url = getClass().getClassLoader().getResource(KernelConstants.JAAS_CONFIG);
44 System.setProperty("java.security.auth.login.config", url.toExternalForm());
45 // log.debug("JASS config: " + url.toExternalForm());
46 // disable Jetty autostart
47 // System.setProperty("org.eclipse.equinox.http.jetty.autostart",
48 // "false");
49
50 firstInit = !new File(getOsgiInstanceDir(), DIR_NODE).exists();
51
52 this.keyStoreFile = new File(KernelUtils.getOsgiInstanceDir(), "node.p12");
53 createKeyStoreIfNeeded();
54 if (keyStoreFile.exists())
55 this.kernelSubject = logInHardenedKernel();
56 else
57 this.kernelSubject = logInKernel();
58 }
59
60 private Subject logInKernel() {
61 final Subject kernelSubject = new Subject();
62 try {
63 LoginContext kernelLc = new LoginContext(KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
64 kernelLc.login();
65 } catch (LoginException e) {
66 throw new CmsException("Cannot log in kernel", e);
67 }
68 return kernelSubject;
69 }
70
71 private Subject logInHardenedKernel() {
72 final Subject kernelSubject = new Subject();
73 createKeyStoreIfNeeded();
74
75 CallbackHandler cbHandler = new CallbackHandler() {
76
77 @Override
78 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
79 // alias
80 ((NameCallback) callbacks[1]).setName(AuthConstants.ROLE_KERNEL);
81 // store pwd
82 ((PasswordCallback) callbacks[2]).setPassword("changeit".toCharArray());
83 // key pwd
84 ((PasswordCallback) callbacks[3]).setPassword("changeit".toCharArray());
85 }
86 };
87 try {
88 LoginContext kernelLc = new LoginContext(KernelConstants.LOGIN_CONTEXT_HARDENED_KERNEL, kernelSubject,
89 cbHandler);
90 kernelLc.login();
91 } catch (LoginException e) {
92 throw new CmsException("Cannot log in kernel", e);
93 }
94 return kernelSubject;
95 }
96
97 void destroy() {
98 // Logout kernel
99 try {
100 LoginContext kernelLc = new LoginContext(KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
101 kernelLc.logout();
102 } catch (LoginException e) {
103 throw new CmsException("Cannot log out kernel", e);
104 }
105
106 // Security.removeProvider(SECURITY_PROVIDER);
107 }
108
109 public Subject getKernelSubject() {
110 return kernelSubject;
111 }
112
113 public synchronized int getSecurityLevel() {
114 return securityLevel;
115 }
116
117 public boolean isFirstInit() {
118 return firstInit;
119 }
120
121 public void setSecurityLevel(int newValue) {
122 if (newValue != STAGING || newValue != DEV)
123 throw new CmsException("Invalid value for security level " + newValue);
124 if (newValue >= securityLevel)
125 throw new CmsException(
126 "Impossible to increase security level (from " + securityLevel + " to " + newValue + ")");
127 securityLevel = newValue;
128 }
129
130 private void createKeyStoreIfNeeded() {
131 // for (Provider provider : Security.getProviders())
132 // System.out.println(provider.getName());
133
134 char[] ksPwd = "changeit".toCharArray();
135 char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length);
136 if (!keyStoreFile.exists()) {
137 try {
138 keyStoreFile.getParentFile().mkdirs();
139 KeyStore keyStore = PkiUtils.getKeyStore(keyStoreFile, ksPwd);
140 PkiUtils.generateSelfSignedCertificate(keyStore, new X500Principal(AuthConstants.ROLE_KERNEL), 1024,
141 keyPwd);
142 PkiUtils.saveKeyStore(keyStoreFile, ksPwd, keyStore);
143 if (log.isDebugEnabled())
144 log.debug("Created keystore " + keyStoreFile);
145 } catch (Exception e) {
146 if (keyStoreFile.length() == 0)
147 keyStoreFile.delete();
148 log.error("Cannot create keystore " + keyStoreFile, e);
149 }
150 }
151 }
152
153 File getHttpServerKeyStore() {
154 return keyStoreFile;
155 }
156
157 // private final static String SECURITY_PROVIDER = "BC";// Bouncy Castle
158 // private final static Log log;
159 // static {
160 // log = LogFactory.getLog(NodeSecurity.class);
161 // // Make Bouncy Castle the default provider
162 // Provider provider = new BouncyCastleProvider();
163 // int position = Security.insertProviderAt(provider, 1);
164 // if (position == -1)
165 // log.error("Provider " + provider.getName()
166 // + " already installed and could not be set as default");
167 // Provider defaultProvider = Security.getProviders()[0];
168 // if (!defaultProvider.getName().equals(SECURITY_PROVIDER))
169 // log.error("Provider name is " + defaultProvider.getName()
170 // + " but it should be " + SECURITY_PROVIDER);
171 // }
172 }