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 }