blob: bc4a0bd857e95d83389bd595e20bc75f80824454 [file] [log] [blame]
Karl Pauls36407322008-03-07 00:37:30 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.framework;
20
21import java.io.File;
22import java.io.IOException;
Karl Pauls36407322008-03-07 00:37:30 +000023import java.util.StringTokenizer;
Karl Pauls36407322008-03-07 00:37:30 +000024
Karl Pauls23287bd2010-01-10 22:11:27 +000025import org.apache.felix.framework.ext.SecurityProvider;
Karl Pauls36407322008-03-07 00:37:30 +000026import org.apache.felix.framework.security.SecurityConstants;
27import org.apache.felix.framework.security.condpermadmin.ConditionalPermissionAdminImpl;
28import org.apache.felix.framework.security.permissionadmin.PermissionAdminImpl;
29import org.apache.felix.framework.security.util.Conditions;
30import org.apache.felix.framework.security.util.LocalPermissions;
31import org.apache.felix.framework.security.util.Permissions;
32import org.apache.felix.framework.security.util.PropertiesCache;
Karl Pauls36407322008-03-07 00:37:30 +000033import org.apache.felix.framework.util.SecureAction;
Karl Pauls36407322008-03-07 00:37:30 +000034import org.osgi.framework.BundleActivator;
35import org.osgi.framework.BundleContext;
36import org.osgi.framework.BundleException;
Karl Pauls23287bd2010-01-10 22:11:27 +000037import org.osgi.framework.Constants;
Karl Pauls36407322008-03-07 00:37:30 +000038import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
39import org.osgi.service.permissionadmin.PermissionAdmin;
40
41/**
Karl Pauls23287bd2010-01-10 22:11:27 +000042 * <p>
43 * This Felix specific activator installs a security provider with the Felix
Karl Pauls36407322008-03-07 00:37:30 +000044 * framework. The security settings can be changed via the
Karl Pauls23287bd2010-01-10 22:11:27 +000045 * {@link PermissionAdmin} and/or the {@link ConditionalPermissionAdmin}
46 * services that may be published by this class.
Karl Pauls36407322008-03-07 00:37:30 +000047 * </p>
48 * <p>
Karl Pauls23287bd2010-01-10 22:11:27 +000049 * Permission informations as well as caching data will be stored in several
50 * files in a directory called <tt>security</tt> obtained by a call to
Karl Pauls36407322008-03-07 00:37:30 +000051 * {@link BundleContext#getDataFile(String))}.
52 * </p>
53 * <p>
54 * The following properties are recognized:
55 * <p>
Karl Pauls23287bd2010-01-10 22:11:27 +000056 * {@link SecurityConstants#ENABLE_PERMISSIONADMIN_PROP} - Whether or not (
57 * <tt>true</tt>|<tt>false</tt>) to publish a{@link ConditionalPermissionAdmin}
58 * service. The default is
Karl Pauls36407322008-03-07 00:37:30 +000059 * {@link SecurityConstants#ENABLE_PERMISSIONADMIN_VALUE}.
60 * </p>
61 * <p>
Karl Pauls23287bd2010-01-10 22:11:27 +000062 * {@link SecurityConstants#ENABLE_CONDPERMADMIN_PROP} - Whether or not (
63 * <tt>true</tt>|<tt>false</tt>) to publish a{@link ConditionalPermissionAdmin}
64 * service. The default is {@link SecurityConstants#ENABLE_CONDPERMADMIN_VALUE}.
Karl Pauls36407322008-03-07 00:37:30 +000065 * </p>
66 * <p>
67 * {@link SecurityConstants#KEYSTORE_FILE_PROP} - The keystore URL(s) to use as
68 * trusted CA stores. The urls must be separated by a guard (i.e., <tt>|</tt>).
Karl Pauls23287bd2010-01-10 22:11:27 +000069 * The default is {@link SecurityConstants#KEYSTORE_FILE_VALUE}.
Karl Pauls36407322008-03-07 00:37:30 +000070 * </p>
71 * <p>
72 * {@link SecurityConstants#KEYSTORE_PASS_PROP} - The keystore password(s) to
Karl Pauls23287bd2010-01-10 22:11:27 +000073 * use for the given keystores. The passwords must be separated by a guard
Karl Pauls36407322008-03-07 00:37:30 +000074 * (i.e., <tt>|</tt>).The default is
75 * {@link SecurityConstants#KEYSTORE_PASS_VALUE}.
76 * </p>
77 * <p>
78 * {@link SecurityConstants#KEYSTORE_TYPE_PROP} - The keystore type(s) to use
Karl Pauls23287bd2010-01-10 22:11:27 +000079 * for the given keystores. The types must be separated by a guard (i.e.,
80 * <tt>|</tt>).The default is {@link SecurityConstants#KEYSTORE_TYPE_VALUE}.
Karl Pauls36407322008-03-07 00:37:30 +000081 * </p>
82 * <p>
83 * {@link SecurityConstants#CRL_FILE_PROP} - The CRL URL(s) to use for revoked
Karl Pauls23287bd2010-01-10 22:11:27 +000084 * certificates. The urls must be separated by a guard (i.e., <tt>|</tt>). The
85 * default is {@link SecurityConstants#CRL_FILE_VALUE}.
Karl Pauls36407322008-03-07 00:37:30 +000086 * </p>
87 * </p>
88 */
89/*
90 * TODO: using a string for passwords is bad. We need to investigate
Karl Pauls23287bd2010-01-10 22:11:27 +000091 * alternatives.
Karl Pauls36407322008-03-07 00:37:30 +000092 *
Karl Pauls23287bd2010-01-10 22:11:27 +000093 * TODO: we might want to allow for the recognized properties to change without
94 * a restart. This is trick because we can not publish a managed service due to
95 * not being able to import as we are an extension bundle.
Karl Pauls36407322008-03-07 00:37:30 +000096 */
97public final class SecurityActivator implements BundleActivator
98{
Karl Pauls36407322008-03-07 00:37:30 +000099 public synchronized void start(BundleContext context) throws Exception
100 {
101 PermissionAdminImpl pai = null;
102
103 SecureAction action = new SecureAction();
104
105 Permissions permissions = new Permissions(context, action);
106
107 File tmp = context.getDataFile("security" + File.separator + "tmp");
108 if ((tmp == null) || (!tmp.isDirectory() && !tmp.mkdirs()))
109 {
110 throw new IOException("Can't create tmp dir.");
111 }
112 // TODO: log something if we can not clean-up the tmp dir
113 File[] old = tmp.listFiles();
114 if (old != null)
115 {
116 for (int i = 0; i < old.length; i++)
117 {
118 old[i].delete();
119 }
120 }
121
122 if ("TRUE".equalsIgnoreCase(getProperty(context,
123 SecurityConstants.ENABLE_PERMISSIONADMIN_PROP,
124 SecurityConstants.ENABLE_PERMISSIONADMIN_VALUE)))
125 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000126 File cache = context.getDataFile("security" + File.separator
127 + "pa.txt");
Karl Pauls36407322008-03-07 00:37:30 +0000128 if ((cache == null) || (!cache.isFile() && !cache.createNewFile()))
129 {
130 throw new IOException("Can't create cache file");
131 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000132 pai = new PermissionAdminImpl(permissions, new PropertiesCache(
133 cache, tmp, action));
Karl Pauls36407322008-03-07 00:37:30 +0000134 }
135
136 ConditionalPermissionAdminImpl cpai = null;
137
138 if ("TRUE".equalsIgnoreCase(getProperty(context,
139 SecurityConstants.ENABLE_CONDPERMADMIN_PROP,
140 SecurityConstants.ENABLE_CONDPERMADMIN_VALUE)))
141 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000142 File cpaCache = context.getDataFile("security" + File.separator
143 + "cpa.txt");
144 if ((cpaCache == null)
145 || (!cpaCache.isFile() && !cpaCache.createNewFile()))
Karl Pauls36407322008-03-07 00:37:30 +0000146 {
147 throw new IOException("Can't create cache file");
148 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000149
150 LocalPermissions localPermissions = new LocalPermissions(
151 permissions);
152
153 cpai = new ConditionalPermissionAdminImpl(permissions,
154 new Conditions(action), localPermissions, new PropertiesCache(
155 cpaCache, tmp, action), pai);
Karl Pauls36407322008-03-07 00:37:30 +0000156 }
157
158 if ((pai != null) || (cpai != null))
159 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000160 String crlList = getProperty(context,
161 SecurityConstants.CRL_FILE_PROP,
162 SecurityConstants.CRL_FILE_VALUE);
163 String storeList = getProperty(context,
164 SecurityConstants.KEYSTORE_FILE_PROP,
165 SecurityConstants.KEYSTORE_FILE_VALUE);
166 String passwdList = getProperty(context,
167 SecurityConstants.KEYSTORE_PASS_PROP,
168 SecurityConstants.KEYSTORE_PASS_VALUE);
169 String typeList = getProperty(context,
170 SecurityConstants.KEYSTORE_TYPE_PROP,
171 SecurityConstants.KEYSTORE_TYPE_VALUE);
172 String osgi_keystores = getProperty(context,
173 Constants.FRAMEWORK_TRUST_REPOSITORIES, null);
174 if (osgi_keystores != null)
175 {
176 StringTokenizer tok = new StringTokenizer(osgi_keystores,
177 File.pathSeparator);
178
179 if (storeList.length() == 0)
180 {
181 storeList += "file:" + tok.nextToken();
182 passwdList += " ";
183 typeList += "JKS";
184 }
185 while (tok.hasMoreTokens())
186 {
187 storeList += "|file:" + tok.nextToken();
188 passwdList += "| ";
189 typeList += "|JKS";
190 }
191 }
Karl Pauls36407322008-03-07 00:37:30 +0000192
193 StringTokenizer storeTok = new StringTokenizer(storeList, "|");
194 StringTokenizer passwdTok = new StringTokenizer(passwdList, "|");
195 StringTokenizer typeTok = new StringTokenizer(typeList, "|");
196
Karl Pauls23287bd2010-01-10 22:11:27 +0000197 if ((storeTok.countTokens() != typeTok.countTokens())
198 || (passwdTok.countTokens() != storeTok.countTokens()))
Karl Pauls36407322008-03-07 00:37:30 +0000199 {
200 throw new BundleException(
201 "Each CACerts keystore must have one type and one passwd entry and vice versa.");
202 }
203
Karl Pauls23287bd2010-01-10 22:11:27 +0000204 SecurityProvider provider = new SecurityProviderImpl(crlList,
205 typeList, passwdList, storeList, pai, cpai, action);
Karl Pauls36407322008-03-07 00:37:30 +0000206
Karl Pauls23287bd2010-01-10 22:11:27 +0000207 ((Felix) context.getBundle(0)).setSecurityProvider(provider);
Karl Pauls36407322008-03-07 00:37:30 +0000208 }
209
210 if (pai != null)
211 {
212 context.registerService(PermissionAdmin.class.getName(), pai, null);
213 }
214
215 if (cpai != null)
216 {
217 context.registerService(ConditionalPermissionAdmin.class.getName(),
218 cpai, null);
219 }
220 }
221
222 public synchronized void stop(BundleContext context) throws Exception
223 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000224 ((Felix) context.getBundle(0)).setSecurityProvider(null);
Karl Pauls36407322008-03-07 00:37:30 +0000225 }
226
227 private String getProperty(BundleContext context, String key,
228 String defaultValue)
229 {
230 String result = context.getProperty(key);
231
Karl Pauls23287bd2010-01-10 22:11:27 +0000232 return (result != null) ? result : defaultValue;
Karl Pauls36407322008-03-07 00:37:30 +0000233 }
234}