View Javadoc
1   package org.argeo.cms.internal.kernel;
2   
3   import java.io.IOException;
4   import java.net.URL;
5   import java.security.AllPermission;
6   import java.util.List;
7   import java.util.Locale;
8   import java.util.concurrent.ExecutorService;
9   import java.util.concurrent.Executors;
10  
11  import javax.security.auth.login.Configuration;
12  
13  import org.apache.commons.logging.Log;
14  import org.apache.commons.logging.LogFactory;
15  import org.argeo.api.ArgeoLogger;
16  import org.argeo.api.NodeConstants;
17  import org.argeo.api.NodeDeployment;
18  import org.argeo.api.NodeInstance;
19  import org.argeo.api.NodeState;
20  import org.argeo.cms.CmsException;
21  import org.argeo.ident.IdentClient;
22  import org.ietf.jgss.GSSCredential;
23  import org.osgi.framework.BundleActivator;
24  import org.osgi.framework.BundleContext;
25  import org.osgi.framework.Constants;
26  import org.osgi.framework.ServiceReference;
27  import org.osgi.service.condpermadmin.BundleLocationCondition;
28  import org.osgi.service.condpermadmin.ConditionInfo;
29  import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
30  import org.osgi.service.condpermadmin.ConditionalPermissionInfo;
31  import org.osgi.service.condpermadmin.ConditionalPermissionUpdate;
32  import org.osgi.service.log.LogReaderService;
33  import org.osgi.service.permissionadmin.PermissionInfo;
34  import org.osgi.service.useradmin.UserAdmin;
35  import org.osgi.util.tracker.ServiceTracker;
36  
37  /**
38   * Activates the kernel. Gives access to kernel information for the rest of the
39   * bundle (and only it)
40   */
41  public class Activator implements BundleActivator {
42  	private final static Log log = LogFactory.getLog(Activator.class);
43  
44  	private static Activator instance;
45  
46  	// TODO make it configurable
47  	private boolean hardened = false;
48  
49  	private BundleContext bc;
50  
51  	private LogReaderService logReaderService;
52  
53  	private NodeLogger logger;
54  	private CmsState nodeState;
55  	private CmsDeployment nodeDeployment;
56  	private CmsInstance nodeInstance;
57  
58  	private ServiceTracker<UserAdmin, NodeUserAdmin> userAdminSt;
59  	private ExecutorService internalExecutorService;
60  
61  	@Override
62  	public void start(BundleContext bundleContext) throws Exception {
63  		Runtime.getRuntime().addShutdownHook(new CmsShutdown());
64  		instance = this;
65  		this.bc = bundleContext;
66  		this.logReaderService = getService(LogReaderService.class);
67  		this.internalExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
68  
69  		try {
70  			initSecurity();
71  			initArgeoLogger();
72  			initNode();
73  
74  			userAdminSt = new ServiceTracker<>(instance.bc, UserAdmin.class, null);
75  			userAdminSt.open();
76  			if (log.isTraceEnabled())
77  				log.trace("Kernel bundle started");
78  		} catch (Throwable e) {
79  			log.error("## FATAL: CMS activator failed", e);
80  		}
81  	}
82  
83  	private void initSecurity() {
84  		if (System.getProperty(KernelConstants.JAAS_CONFIG_PROP) == null) {
85  			String jaasConfig = KernelConstants.JAAS_CONFIG;
86  			URL url = getClass().getClassLoader().getResource(jaasConfig);
87  			// System.setProperty(KernelConstants.JAAS_CONFIG_PROP,
88  			// url.toExternalForm());
89  			KernelUtils.setJaasConfiguration(url);
90  		}
91  		// explicitly load JAAS configuration
92  		Configuration.getConfiguration();
93  
94  		// code-level permissions
95  		String osgiSecurity = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_SECURITY);
96  		if (osgiSecurity != null && Constants.FRAMEWORK_SECURITY_OSGI.equals(osgiSecurity)) {
97  			// TODO rather use a tracker?
98  			ConditionalPermissionAdmin permissionAdmin = bc
99  					.getService(bc.getServiceReference(ConditionalPermissionAdmin.class));
100 			if (!hardened) {
101 				// All permissions to all bundles
102 				ConditionalPermissionUpdate update = permissionAdmin.newConditionalPermissionUpdate();
103 				update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
104 						new ConditionInfo[] {
105 								new ConditionInfo(BundleLocationCondition.class.getName(), new String[] { "*" }) },
106 						new PermissionInfo[] { new PermissionInfo(AllPermission.class.getName(), null, null) },
107 						ConditionalPermissionInfo.ALLOW));
108 				// TODO data admin permission
109 //				PermissionInfo dataAdminPerm = new PermissionInfo(AuthPermission.class.getName(),
110 //						"createLoginContext." + NodeConstants.LOGIN_CONTEXT_DATA_ADMIN, null);
111 //				update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
112 //						new ConditionInfo[] {
113 //								new ConditionInfo(BundleLocationCondition.class.getName(), new String[] { "*" }) },
114 //						new PermissionInfo[] { dataAdminPerm }, ConditionalPermissionInfo.DENY));
115 //				update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
116 //						new ConditionInfo[] {
117 //								new ConditionInfo(BundleSignerCondition.class.getName(), new String[] { "CN=\"Eclipse.org Foundation, Inc.\", OU=IT, O=\"Eclipse.org Foundation, Inc.\", L=Nepean, ST=Ontario, C=CA" }) },
118 //						new PermissionInfo[] { dataAdminPerm }, ConditionalPermissionInfo.ALLOW));
119 				update.commit();
120 			} else {
121 				SecurityProfile securityProfile = new SecurityProfile() {
122 				};
123 				securityProfile.applySystemPermissions(permissionAdmin);
124 			}
125 		}
126 
127 	}
128 
129 	private void initArgeoLogger() {
130 		logger = new NodeLogger(logReaderService);
131 		bc.registerService(ArgeoLogger.class, logger, null);
132 	}
133 
134 	private void initNode() throws IOException {
135 		// Node state
136 //		Path stateUuidPath = bc.getDataFile("stateUuid").toPath();
137 //		String stateUuid;
138 //		if (Files.exists(stateUuidPath)) {
139 //			stateUuid = Files.readAllLines(stateUuidPath).get(0);
140 //		} else {
141 //			stateUuid = bc.getProperty(Constants.FRAMEWORK_UUID);
142 //			Files.write(stateUuidPath, stateUuid.getBytes());
143 //		}
144 		nodeState = new CmsState();
145 //		Dictionary<String, Object> regProps = LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID);
146 //		regProps.put(NodeConstants.CN, stateUuid);
147 		bc.registerService(NodeState.class, nodeState, null);
148 
149 		// Node deployment
150 		nodeDeployment = new CmsDeployment();
151 		bc.registerService(NodeDeployment.class, nodeDeployment, null);
152 
153 		// Node instance
154 		nodeInstance = new CmsInstance();
155 		bc.registerService(NodeInstance.class, nodeInstance, null);
156 	}
157 
158 	@Override
159 	public void stop(BundleContext bundleContext) throws Exception {
160 		try {
161 			if (nodeInstance != null)
162 				nodeInstance.shutdown();
163 			if (nodeDeployment != null)
164 				nodeDeployment.shutdown();
165 			if (nodeState != null)
166 				nodeState.shutdown();
167 
168 			if (userAdminSt != null)
169 				userAdminSt.close();
170 
171 			internalExecutorService.shutdown();
172 			instance = null;
173 			this.bc = null;
174 			this.logReaderService = null;
175 			// this.configurationAdmin = null;
176 		} catch (Exception e) {
177 			log.error("CMS activator shutdown failed", e);
178 		}
179 	}
180 
181 	private <T> T getService(Class<T> clazz) {
182 		ServiceReference<T> sr = bc.getServiceReference(clazz);
183 		if (sr == null)
184 			throw new CmsException("No service available for " + clazz);
185 		return bc.getService(sr);
186 	}
187 
188 	public static NodeState getNodeState() {
189 		return instance.nodeState;
190 	}
191 
192 	public static GSSCredential getAcceptorCredentials() {
193 		return getNodeUserAdmin().getAcceptorCredentials();
194 	}
195 
196 	public static boolean isSingleUser() {
197 		return getNodeUserAdmin().isSingleUser();
198 	}
199 
200 	public static UserAdmin getUserAdmin() {
201 		return (UserAdmin) getNodeUserAdmin();
202 	}
203 
204 	public static String getHttpProxySslHeader() {
205 		return KernelUtils.getFrameworkProp(NodeConstants.HTTP_PROXY_SSL_DN);
206 	}
207 
208 	public static IdentClient getIdentClient(String remoteAddr) {
209 		if (!IdentClient.isDefaultAuthdPassphraseFileAvailable())
210 			return null;
211 		// TODO make passphrase more configurable
212 		return new IdentClient(remoteAddr);
213 	}
214 
215 	private static NodeUserAdmin getNodeUserAdmin() {
216 		NodeUserAdmin res;
217 		try {
218 			res = instance.userAdminSt.waitForService(60000);
219 		} catch (InterruptedException e) {
220 			throw new CmsException("Cannot retrieve Node user admin", e);
221 		}
222 		if (res == null)
223 			throw new CmsException("No Node user admin found");
224 
225 		return res;
226 		// ServiceReference<UserAdmin> sr =
227 		// instance.bc.getServiceReference(UserAdmin.class);
228 		// NodeUserAdmin userAdmin = (NodeUserAdmin) instance.bc.getService(sr);
229 		// return userAdmin;
230 
231 	}
232 
233 	static ExecutorService getInternalExecutorService() {
234 		return instance.internalExecutorService;
235 	}
236 
237 	// static CmsSecurity getCmsSecurity() {
238 	// return instance.nodeSecurity;
239 	// }
240 
241 	public String[] getLocales() {
242 		// TODO optimize?
243 		List<Locale> locales = getNodeState().getLocales();
244 		String[] res = new String[locales.size()];
245 		for (int i = 0; i < locales.size(); i++)
246 			res[i] = locales.get(i).toString();
247 		return res;
248 	}
249 
250 }