001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.security.deployment;
019
020 import java.security.Principal;
021 import java.util.HashMap;
022 import java.util.HashSet;
023 import java.util.Map;
024 import java.util.Set;
025 import java.util.Collections;
026
027 import javax.xml.namespace.QName;
028
029 import org.apache.geronimo.common.DeploymentException;
030 import org.apache.geronimo.deployment.DeploymentContext;
031 import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
032 import org.apache.geronimo.deployment.service.SingleGBeanBuilder;
033 import org.apache.geronimo.deployment.xbeans.PatternType;
034 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
035 import org.apache.geronimo.gbean.AbstractName;
036 import org.apache.geronimo.gbean.GBeanData;
037 import org.apache.geronimo.gbean.GBeanInfo;
038 import org.apache.geronimo.gbean.GBeanInfoBuilder;
039 import org.apache.geronimo.gbean.AbstractNameQuery;
040 import org.apache.geronimo.gbean.GBeanLifecycle;
041 import org.apache.geronimo.j2ee.deployment.EARContext;
042 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
043 import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
044 import org.apache.geronimo.kernel.Naming;
045 import org.apache.geronimo.kernel.repository.Environment;
046 import org.apache.geronimo.security.deploy.LoginDomainPrincipalInfo;
047 import org.apache.geronimo.security.deploy.PrincipalInfo;
048 import org.apache.geronimo.security.deploy.RealmPrincipalInfo;
049 import org.apache.geronimo.security.deploy.Role;
050 import org.apache.geronimo.security.deploy.Security;
051 import org.apache.geronimo.security.deploy.SubjectInfo;
052 import org.apache.geronimo.security.jacc.ApplicationPolicyConfigurationManager;
053 import org.apache.geronimo.security.jacc.mappingprovider.ApplicationPrincipalRoleConfigurationManager;
054 import org.apache.geronimo.security.util.ConfigurationUtil;
055 import org.apache.geronimo.security.credentialstore.CredentialStore;
056 import org.apache.geronimo.xbeans.geronimo.security.GerLoginDomainPrincipalType;
057 import org.apache.geronimo.xbeans.geronimo.security.GerPrincipalType;
058 import org.apache.geronimo.xbeans.geronimo.security.GerRealmPrincipalType;
059 import org.apache.geronimo.xbeans.geronimo.security.GerRoleMappingsType;
060 import org.apache.geronimo.xbeans.geronimo.security.GerRoleType;
061 import org.apache.geronimo.xbeans.geronimo.security.GerSecurityDocument;
062 import org.apache.geronimo.xbeans.geronimo.security.GerSecurityType;
063 import org.apache.geronimo.xbeans.geronimo.security.GerSubjectInfoType;
064 import org.apache.xmlbeans.QNameSet;
065 import org.apache.xmlbeans.XmlException;
066 import org.apache.xmlbeans.XmlObject;
067
068 /**
069 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
070 */
071 public class GeronimoSecurityBuilderImpl implements NamespaceDrivenBuilder, GBeanLifecycle {
072 private static final QName SECURITY_QNAME = GerSecurityDocument.type.getDocumentElementName();
073 private static final QNameSet SECURITY_QNAME_SET = QNameSet.singleton(SECURITY_QNAME);
074 private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>();
075 static {
076 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/loginconfig", "http://geronimo.apache.org/xml/ns/loginconfig-2.0");
077 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/loginconfig-1.1", "http://geronimo.apache.org/xml/ns/loginconfig-2.0");
078 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/loginconfig-1.2", "http://geronimo.apache.org/xml/ns/loginconfig-2.0");
079 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/security", "http://geronimo.apache.org/xml/ns/security-1.2");
080 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/security-1.1", "http://geronimo.apache.org/xml/ns/security-2.0");
081 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/security-1.2", "http://geronimo.apache.org/xml/ns/security-2.0");
082 }
083
084 private final AbstractNameQuery credentialStoreName;
085
086 public GeronimoSecurityBuilderImpl(AbstractNameQuery credentialStoreName) {
087 this.credentialStoreName = credentialStoreName;
088 }
089
090 public void doStart() {
091 XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES);
092 }
093
094 public void doStop() {
095 XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES);
096 }
097
098 public void doFail() {
099 doStop();
100 }
101
102 public void buildEnvironment(XmlObject container, Environment environment) throws DeploymentException {
103 }
104
105 public void build(XmlObject container, DeploymentContext applicationContext, DeploymentContext moduleContext) throws DeploymentException {
106 EARContext earContext = (EARContext) applicationContext;
107 XmlObject[] items = container.selectChildren(SECURITY_QNAME_SET);
108 if (items.length > 1) {
109 throw new DeploymentException("Unexpected count of security elements in geronimo plan " + items.length + " qnameset: " + SECURITY_QNAME_SET);
110 }
111 if (items.length == 1) {
112 GerSecurityType securityType;
113 try {
114 securityType = (GerSecurityType) XmlBeansUtil.typedCopy(items[0], GerSecurityType.type);
115 } catch (XmlException e) {
116 throw new DeploymentException("Could not validate security element", e);
117 }
118 Security security = buildSecurityConfig(securityType);
119 ClassLoader classLoader = applicationContext.getClassLoader();
120 SecurityConfiguration securityConfiguration = buildSecurityConfiguration(security, classLoader);
121 earContext.setSecurityConfiguration(securityConfiguration);
122
123 Naming naming = earContext.getNaming();
124 GBeanData roleMapperData = configureRoleMapper(naming, earContext.getModuleName(), securityConfiguration);
125 try {
126 earContext.addGBean(roleMapperData);
127 } catch (GBeanAlreadyExistsException e) {
128 throw new DeploymentException("Role mapper gbean already present", e);
129 }
130 AbstractNameQuery credentialStoreName;
131 if (securityType.isSetCredentialStoreRef()) {
132 PatternType credentialStoreType = securityType.getCredentialStoreRef();
133 credentialStoreName = SingleGBeanBuilder.buildAbstractNameQuery(credentialStoreType, NameFactory.GERONIMO_SERVICE, Collections.singleton(CredentialStore.class.getName()));
134 } else {
135 credentialStoreName = this.credentialStoreName;
136 }
137 GBeanData jaccBeanData = configureApplicationPolicyManager(naming, earContext.getModuleName(), earContext.getContextIDToPermissionsMap(), securityConfiguration, credentialStoreName);
138 jaccBeanData.setReferencePattern("PrincipalRoleMapper", roleMapperData.getAbstractName());
139 try {
140 earContext.addGBean(jaccBeanData);
141 } catch (GBeanAlreadyExistsException e) {
142 throw new DeploymentException("JACC manager gbean already present", e);
143 }
144 earContext.setJaccManagerName(jaccBeanData.getAbstractName());
145 }
146 }
147
148 private static SecurityConfiguration buildSecurityConfiguration(Security security, ClassLoader classLoader) {
149 Map<String, SubjectInfo> roleDesignates = security.getRoleSubjectMappings();
150 Map<Principal, Set<String>> principalRoleMap = new HashMap<Principal, Set<String>>();
151 Map<String, Set<Principal>> roleToPrincipalMap = new HashMap<String, Set<Principal>>();
152 buildRolePrincipalMap(security, roleToPrincipalMap, classLoader);
153 invertMap(roleToPrincipalMap, principalRoleMap);
154 return new SecurityConfiguration(principalRoleMap, roleDesignates, security.getDefaultSubjectInfo(), security.getDefaultRole(), security.isDoAsCurrentCaller(), security.isUseContextHandler());
155 }
156
157 private static Map invertMap(Map<String, Set<Principal>> roleToPrincipalMap, Map<Principal, Set<String>> principalRoleMapping) {
158 for (Map.Entry<String, Set<java.security.Principal>> entry : roleToPrincipalMap.entrySet()) {
159 String role = entry.getKey();
160 Set<Principal> principals = entry.getValue();
161 for (Principal principal : principals) {
162
163 Set<String> roleSet = principalRoleMapping.get(principal);
164 if (roleSet == null) {
165 roleSet = new HashSet<String>();
166 principalRoleMapping.put(principal, roleSet);
167 }
168 roleSet.add(role);
169 }
170 }
171 return principalRoleMapping;
172 }
173
174 /**
175 * non-interface, used in some jetty/tomcat tests
176 *
177 * @param security Security object holding security info as it is extracted
178 * @param roleToPrincipalMap role to set of Principals mapping
179 * @param classLoader application classloader in case we need to load some principal classes.
180 */
181 public static void buildRolePrincipalMap(Security security, Map<String, Set<Principal>> roleToPrincipalMap, ClassLoader classLoader) {
182
183 for (Object o : security.getRoleMappings().values()) {
184 Role role = (Role) o;
185
186 String roleName = role.getRoleName();
187 Set<Principal> principalSet = new HashSet<Principal>();
188
189 for (Object o1 : role.getRealmPrincipals()) {
190 RealmPrincipalInfo realmPrincipal = (RealmPrincipalInfo) o1;
191 Principal principal = ConfigurationUtil.generateRealmPrincipal(realmPrincipal.getRealm(), realmPrincipal.getDomain(), realmPrincipal, classLoader);
192
193 principalSet.add(principal);
194 }
195
196 for (Object o2 : role.getLoginDomainPrincipals()) {
197 LoginDomainPrincipalInfo domainPrincipal = (LoginDomainPrincipalInfo) o2;
198 Principal principal = ConfigurationUtil.generateDomainPrincipal(domainPrincipal.getDomain(), domainPrincipal, classLoader);
199
200 principalSet.add(principal);
201 }
202
203 for (Object o3 : role.getPrincipals()) {
204 PrincipalInfo plainPrincipalInfo = (PrincipalInfo) o3;
205 Principal principal = ConfigurationUtil.generatePrincipal(plainPrincipalInfo, classLoader);
206
207 principalSet.add(principal);
208 }
209
210 Set<Principal> roleMapping = roleToPrincipalMap.get(roleName);
211 if (roleMapping == null) {
212 roleMapping = new HashSet<Principal>();
213 roleToPrincipalMap.put(roleName, roleMapping);
214 }
215 roleMapping.addAll(principalSet);
216
217 }
218 }
219
220 private Security buildSecurityConfig(GerSecurityType securityType) {
221 Security security;
222
223 if (securityType == null) {
224 return null;
225 }
226 security = new Security();
227
228 security.setDoAsCurrentCaller(securityType.getDoasCurrentCaller());
229 security.setUseContextHandler(securityType.getUseContextHandler());
230 if (securityType.isSetDefaultRole()) {
231 security.setDefaultRole(securityType.getDefaultRole().trim());
232 }
233
234 if (securityType.isSetRoleMappings()) {
235 GerRoleMappingsType roleMappingsType = securityType.getRoleMappings();
236 for (int i = 0; i < roleMappingsType.sizeOfRoleArray(); i++) {
237 GerRoleType roleType = roleMappingsType.getRoleArray(i);
238 Role role = new Role();
239
240 String roleName = roleType.getRoleName().trim();
241 role.setRoleName(roleName);
242
243 if (roleType.isSetRunAsSubject()) {
244 SubjectInfo subjectInfo = buildSubjectInfo(roleType.getRunAsSubject());
245 security.getRoleSubjectMappings().put(roleName, subjectInfo);
246 }
247
248 for (int j = 0; j < roleType.sizeOfRealmPrincipalArray(); j++) {
249 role.getRealmPrincipals().add(GeronimoSecurityBuilderImpl.buildRealmPrincipal(roleType.getRealmPrincipalArray(j)));
250 }
251
252 for (int j = 0; j < roleType.sizeOfLoginDomainPrincipalArray(); j++) {
253 role.getLoginDomainPrincipals().add(GeronimoSecurityBuilderImpl.buildDomainPrincipal(roleType.getLoginDomainPrincipalArray(j)));
254 }
255
256 for (int j = 0; j < roleType.sizeOfPrincipalArray(); j++) {
257 role.getPrincipals().add(buildPrincipal(roleType.getPrincipalArray(j)));
258 }
259
260 security.getRoleMappings().put(roleName, role);
261 }
262 }
263
264 security.setDefaultSubjectInfo(buildSubjectInfo(securityType.getDefaultSubject()));
265
266 return security;
267 }
268
269 private SubjectInfo buildSubjectInfo(GerSubjectInfoType defaultSubject) {
270 if (defaultSubject == null) {
271 return null;
272 }
273 String realmName = defaultSubject.getRealm().trim();
274 String id = defaultSubject.getId().trim();
275 return new SubjectInfo(realmName, id);
276 }
277
278 private static RealmPrincipalInfo buildRealmPrincipal(GerRealmPrincipalType realmPrincipalType) {
279 return new RealmPrincipalInfo(realmPrincipalType.getRealmName().trim(), realmPrincipalType.getDomainName().trim(), realmPrincipalType.getClass1().trim(), realmPrincipalType.getName().trim());
280 }
281
282 private static LoginDomainPrincipalInfo buildDomainPrincipal(GerLoginDomainPrincipalType domainPrincipalType) {
283 return new LoginDomainPrincipalInfo(domainPrincipalType.getDomainName().trim(), domainPrincipalType.getClass1().trim(), domainPrincipalType.getName().trim());
284 }
285
286 //used from TSSConfigEditor
287 public PrincipalInfo buildPrincipal(XmlObject xmlObject) {
288 GerPrincipalType principalType = (GerPrincipalType) xmlObject;
289 return new PrincipalInfo(principalType.getClass1().trim(), principalType.getName().trim());
290 }
291
292 protected GBeanData configureRoleMapper(Naming naming, AbstractName moduleName, SecurityConfiguration securityConfiguration) {
293 AbstractName roleMapperName = naming.createChildName(moduleName, "RoleMapper", "RoleMapper");
294 GBeanData roleMapperData = new GBeanData(roleMapperName, ApplicationPrincipalRoleConfigurationManager.GBEAN_INFO);
295 roleMapperData.setAttribute("principalRoleMap", securityConfiguration.getPrincipalRoleMap());
296 return roleMapperData;
297 }
298
299 protected GBeanData configureApplicationPolicyManager(Naming naming, AbstractName moduleName, Map contextIDToPermissionsMap, SecurityConfiguration securityConfiguration, AbstractNameQuery credentialStoreName) {
300 AbstractName jaccBeanName = naming.createChildName(moduleName, NameFactory.JACC_MANAGER, NameFactory.JACC_MANAGER);
301 GBeanData jaccBeanData = new GBeanData(jaccBeanName, ApplicationPolicyConfigurationManager.GBEAN_INFO);
302 jaccBeanData.setAttribute("contextIdToPermissionsMap", contextIDToPermissionsMap);
303 Map<String, SubjectInfo> roleDesignates = securityConfiguration.getRoleDesignates();
304 jaccBeanData.setAttribute("roleDesignates", roleDesignates);
305 jaccBeanData.setAttribute("defaultSubjectInfo", securityConfiguration.getDefaultSubjectInfo());
306 if ((roleDesignates != null && !roleDesignates.isEmpty()) || securityConfiguration.getDefaultSubjectInfo() != null) {
307 jaccBeanData.setReferencePattern("CredentialStore", credentialStoreName);
308 }
309 return jaccBeanData;
310 }
311
312 public QNameSet getSpecQNameSet() {
313 return QNameSet.EMPTY;
314 }
315
316 public QNameSet getPlanQNameSet() {
317 return SECURITY_QNAME_SET;
318 }
319
320 public static final GBeanInfo GBEAN_INFO;
321
322 static {
323 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(GeronimoSecurityBuilderImpl.class, NameFactory.MODULE_BUILDER);
324
325 infoFactory.addAttribute("credentialStoreName", AbstractNameQuery.class, true, true);
326 infoFactory.setConstructor(new String[] {"credentialStoreName"});
327
328 GBEAN_INFO = infoFactory.getBeanInfo();
329 }
330
331 public static GBeanInfo getGBeanInfo() {
332 return GBEAN_INFO;
333 }
334
335 }