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: */package org.apache.geronimo.security.deployment;
017:
018: import java.security.Principal;
019: import java.util.HashMap;
020: import java.util.HashSet;
021: import java.util.Map;
022: import java.util.Set;
023: import java.util.Collections;
024:
025: import javax.xml.namespace.QName;
026:
027: import org.apache.geronimo.common.DeploymentException;
028: import org.apache.geronimo.deployment.DeploymentContext;
029: import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
030: import org.apache.geronimo.deployment.service.SingleGBeanBuilder;
031: import org.apache.geronimo.deployment.xbeans.PatternType;
032: import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
033: import org.apache.geronimo.gbean.AbstractName;
034: import org.apache.geronimo.gbean.GBeanData;
035: import org.apache.geronimo.gbean.GBeanInfo;
036: import org.apache.geronimo.gbean.GBeanInfoBuilder;
037: import org.apache.geronimo.gbean.AbstractNameQuery;
038: import org.apache.geronimo.gbean.GBeanLifecycle;
039: import org.apache.geronimo.j2ee.deployment.EARContext;
040: import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
041: import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
042: import org.apache.geronimo.kernel.Naming;
043: import org.apache.geronimo.kernel.repository.Environment;
044: import org.apache.geronimo.security.deploy.LoginDomainPrincipalInfo;
045: import org.apache.geronimo.security.deploy.PrincipalInfo;
046: import org.apache.geronimo.security.deploy.RealmPrincipalInfo;
047: import org.apache.geronimo.security.deploy.Role;
048: import org.apache.geronimo.security.deploy.Security;
049: import org.apache.geronimo.security.deploy.SubjectInfo;
050: import org.apache.geronimo.security.jacc.ApplicationPolicyConfigurationManager;
051: import org.apache.geronimo.security.jacc.mappingprovider.ApplicationPrincipalRoleConfigurationManager;
052: import org.apache.geronimo.security.util.ConfigurationUtil;
053: import org.apache.geronimo.security.credentialstore.CredentialStore;
054: import org.apache.geronimo.xbeans.geronimo.security.GerLoginDomainPrincipalType;
055: import org.apache.geronimo.xbeans.geronimo.security.GerPrincipalType;
056: import org.apache.geronimo.xbeans.geronimo.security.GerRealmPrincipalType;
057: import org.apache.geronimo.xbeans.geronimo.security.GerRoleMappingsType;
058: import org.apache.geronimo.xbeans.geronimo.security.GerRoleType;
059: import org.apache.geronimo.xbeans.geronimo.security.GerSecurityDocument;
060: import org.apache.geronimo.xbeans.geronimo.security.GerSecurityType;
061: import org.apache.geronimo.xbeans.geronimo.security.GerSubjectInfoType;
062: import org.apache.xmlbeans.QNameSet;
063: import org.apache.xmlbeans.XmlException;
064: import org.apache.xmlbeans.XmlObject;
065:
066: /**
067: * @version $Rev: 613094 $ $Date: 2008-01-18 00:00:10 -0800 (Fri, 18 Jan 2008) $
068: */
069: public class GeronimoSecurityBuilderImpl implements
070: NamespaceDrivenBuilder, GBeanLifecycle {
071: private static final QName SECURITY_QNAME = GerSecurityDocument.type
072: .getDocumentElementName();
073: private static final QNameSet SECURITY_QNAME_SET = QNameSet
074: .singleton(SECURITY_QNAME);
075: private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>();
076: static {
077: NAMESPACE_UPDATES.put(
078: "http://geronimo.apache.org/xml/ns/loginconfig",
079: "http://geronimo.apache.org/xml/ns/loginconfig-2.0");
080: NAMESPACE_UPDATES.put(
081: "http://geronimo.apache.org/xml/ns/loginconfig-1.1",
082: "http://geronimo.apache.org/xml/ns/loginconfig-2.0");
083: NAMESPACE_UPDATES.put(
084: "http://geronimo.apache.org/xml/ns/loginconfig-1.2",
085: "http://geronimo.apache.org/xml/ns/loginconfig-2.0");
086: NAMESPACE_UPDATES.put(
087: "http://geronimo.apache.org/xml/ns/security",
088: "http://geronimo.apache.org/xml/ns/security-1.2");
089: NAMESPACE_UPDATES.put(
090: "http://geronimo.apache.org/xml/ns/security-1.1",
091: "http://geronimo.apache.org/xml/ns/security-2.0");
092: NAMESPACE_UPDATES.put(
093: "http://geronimo.apache.org/xml/ns/security-1.2",
094: "http://geronimo.apache.org/xml/ns/security-2.0");
095: }
096:
097: private final AbstractNameQuery credentialStoreName;
098:
099: public GeronimoSecurityBuilderImpl(
100: AbstractNameQuery credentialStoreName) {
101: this .credentialStoreName = credentialStoreName;
102: }
103:
104: public void doStart() {
105: XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES);
106: }
107:
108: public void doStop() {
109: XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES);
110: }
111:
112: public void doFail() {
113: doStop();
114: }
115:
116: public void buildEnvironment(XmlObject container,
117: Environment environment) throws DeploymentException {
118: }
119:
120: public void build(XmlObject container,
121: DeploymentContext applicationContext,
122: DeploymentContext moduleContext) throws DeploymentException {
123: EARContext earContext = (EARContext) applicationContext;
124: XmlObject[] items = container
125: .selectChildren(SECURITY_QNAME_SET);
126: if (items.length > 1) {
127: throw new DeploymentException(
128: "Unexpected count of security elements in geronimo plan "
129: + items.length + " qnameset: "
130: + SECURITY_QNAME_SET);
131: }
132: if (items.length == 1) {
133: GerSecurityType securityType;
134: try {
135: securityType = (GerSecurityType) XmlBeansUtil
136: .typedCopy(items[0], GerSecurityType.type);
137: } catch (XmlException e) {
138: throw new DeploymentException(
139: "Could not validate security element", e);
140: }
141: Security security = buildSecurityConfig(securityType);
142: ClassLoader classLoader = applicationContext
143: .getClassLoader();
144: SecurityConfiguration securityConfiguration = buildSecurityConfiguration(
145: security, classLoader);
146: earContext.setSecurityConfiguration(securityConfiguration);
147:
148: Naming naming = earContext.getNaming();
149: GBeanData roleMapperData = configureRoleMapper(naming,
150: earContext.getModuleName(), securityConfiguration);
151: try {
152: earContext.addGBean(roleMapperData);
153: } catch (GBeanAlreadyExistsException e) {
154: throw new DeploymentException(
155: "Role mapper gbean already present", e);
156: }
157: AbstractNameQuery credentialStoreName;
158: if (securityType.isSetCredentialStoreRef()) {
159: PatternType credentialStoreType = securityType
160: .getCredentialStoreRef();
161: credentialStoreName = SingleGBeanBuilder
162: .buildAbstractNameQuery(
163: credentialStoreType,
164: NameFactory.GERONIMO_SERVICE,
165: Collections
166: .singleton(CredentialStore.class
167: .getName()));
168: } else {
169: credentialStoreName = this .credentialStoreName;
170: }
171: GBeanData jaccBeanData = configureApplicationPolicyManager(
172: naming, earContext.getModuleName(), earContext
173: .getContextIDToPermissionsMap(),
174: securityConfiguration, credentialStoreName);
175: jaccBeanData.setReferencePattern("PrincipalRoleMapper",
176: roleMapperData.getAbstractName());
177: try {
178: earContext.addGBean(jaccBeanData);
179: } catch (GBeanAlreadyExistsException e) {
180: throw new DeploymentException(
181: "JACC manager gbean already present", e);
182: }
183: earContext.setJaccManagerName(jaccBeanData
184: .getAbstractName());
185: }
186: }
187:
188: private static SecurityConfiguration buildSecurityConfiguration(
189: Security security, ClassLoader classLoader) {
190: Map<String, SubjectInfo> roleDesignates = security
191: .getRoleSubjectMappings();
192: Map<Principal, Set<String>> principalRoleMap = new HashMap<Principal, Set<String>>();
193: Map<String, Set<Principal>> roleToPrincipalMap = new HashMap<String, Set<Principal>>();
194: buildRolePrincipalMap(security, roleToPrincipalMap, classLoader);
195: invertMap(roleToPrincipalMap, principalRoleMap);
196: return new SecurityConfiguration(principalRoleMap,
197: roleDesignates, security.getDefaultSubjectInfo(),
198: security.getDefaultRole(), security
199: .isDoAsCurrentCaller(), security
200: .isUseContextHandler());
201: }
202:
203: private static Map invertMap(
204: Map<String, Set<Principal>> roleToPrincipalMap,
205: Map<Principal, Set<String>> principalRoleMapping) {
206: for (Map.Entry<String, Set<java.security.Principal>> entry : roleToPrincipalMap
207: .entrySet()) {
208: String role = entry.getKey();
209: Set<Principal> principals = entry.getValue();
210: for (Principal principal : principals) {
211:
212: Set<String> roleSet = principalRoleMapping
213: .get(principal);
214: if (roleSet == null) {
215: roleSet = new HashSet<String>();
216: principalRoleMapping.put(principal, roleSet);
217: }
218: roleSet.add(role);
219: }
220: }
221: return principalRoleMapping;
222: }
223:
224: /**
225: * non-interface, used in some jetty/tomcat tests
226: *
227: * @param security Security object holding security info as it is extracted
228: * @param roleToPrincipalMap role to set of Principals mapping
229: * @param classLoader application classloader in case we need to load some principal classes.
230: */
231: public static void buildRolePrincipalMap(Security security,
232: Map<String, Set<Principal>> roleToPrincipalMap,
233: ClassLoader classLoader) {
234:
235: for (Object o : security.getRoleMappings().values()) {
236: Role role = (Role) o;
237:
238: String roleName = role.getRoleName();
239: Set<Principal> principalSet = new HashSet<Principal>();
240:
241: for (Object o1 : role.getRealmPrincipals()) {
242: RealmPrincipalInfo realmPrincipal = (RealmPrincipalInfo) o1;
243: Principal principal = ConfigurationUtil
244: .generateRealmPrincipal(realmPrincipal
245: .getRealm(),
246: realmPrincipal.getDomain(),
247: realmPrincipal, classLoader);
248:
249: principalSet.add(principal);
250: }
251:
252: for (Object o2 : role.getLoginDomainPrincipals()) {
253: LoginDomainPrincipalInfo domainPrincipal = (LoginDomainPrincipalInfo) o2;
254: Principal principal = ConfigurationUtil
255: .generateDomainPrincipal(domainPrincipal
256: .getDomain(), domainPrincipal,
257: classLoader);
258:
259: principalSet.add(principal);
260: }
261:
262: for (Object o3 : role.getPrincipals()) {
263: PrincipalInfo plainPrincipalInfo = (PrincipalInfo) o3;
264: Principal principal = ConfigurationUtil
265: .generatePrincipal(plainPrincipalInfo,
266: classLoader);
267:
268: principalSet.add(principal);
269: }
270:
271: Set<Principal> roleMapping = roleToPrincipalMap
272: .get(roleName);
273: if (roleMapping == null) {
274: roleMapping = new HashSet<Principal>();
275: roleToPrincipalMap.put(roleName, roleMapping);
276: }
277: roleMapping.addAll(principalSet);
278:
279: }
280: }
281:
282: private Security buildSecurityConfig(GerSecurityType securityType) {
283: Security security;
284:
285: if (securityType == null) {
286: return null;
287: }
288: security = new Security();
289:
290: security.setDoAsCurrentCaller(securityType
291: .getDoasCurrentCaller());
292: security.setUseContextHandler(securityType
293: .getUseContextHandler());
294: if (securityType.isSetDefaultRole()) {
295: security.setDefaultRole(securityType.getDefaultRole()
296: .trim());
297: }
298:
299: if (securityType.isSetRoleMappings()) {
300: GerRoleMappingsType roleMappingsType = securityType
301: .getRoleMappings();
302: for (int i = 0; i < roleMappingsType.sizeOfRoleArray(); i++) {
303: GerRoleType roleType = roleMappingsType.getRoleArray(i);
304: Role role = new Role();
305:
306: String roleName = roleType.getRoleName().trim();
307: role.setRoleName(roleName);
308:
309: if (roleType.isSetRunAsSubject()) {
310: SubjectInfo subjectInfo = buildSubjectInfo(roleType
311: .getRunAsSubject());
312: security.getRoleSubjectMappings().put(roleName,
313: subjectInfo);
314: }
315:
316: for (int j = 0; j < roleType
317: .sizeOfRealmPrincipalArray(); j++) {
318: role
319: .getRealmPrincipals()
320: .add(
321: GeronimoSecurityBuilderImpl
322: .buildRealmPrincipal(roleType
323: .getRealmPrincipalArray(j)));
324: }
325:
326: for (int j = 0; j < roleType
327: .sizeOfLoginDomainPrincipalArray(); j++) {
328: role
329: .getLoginDomainPrincipals()
330: .add(
331: GeronimoSecurityBuilderImpl
332: .buildDomainPrincipal(roleType
333: .getLoginDomainPrincipalArray(j)));
334: }
335:
336: for (int j = 0; j < roleType.sizeOfPrincipalArray(); j++) {
337: role.getPrincipals().add(
338: buildPrincipal(roleType
339: .getPrincipalArray(j)));
340: }
341:
342: security.getRoleMappings().put(roleName, role);
343: }
344: }
345:
346: security.setDefaultSubjectInfo(buildSubjectInfo(securityType
347: .getDefaultSubject()));
348:
349: return security;
350: }
351:
352: private SubjectInfo buildSubjectInfo(
353: GerSubjectInfoType defaultSubject) {
354: if (defaultSubject == null) {
355: return null;
356: }
357: String realmName = defaultSubject.getRealm().trim();
358: String id = defaultSubject.getId().trim();
359: return new SubjectInfo(realmName, id);
360: }
361:
362: private static RealmPrincipalInfo buildRealmPrincipal(
363: GerRealmPrincipalType realmPrincipalType) {
364: return new RealmPrincipalInfo(realmPrincipalType.getRealmName()
365: .trim(), realmPrincipalType.getDomainName().trim(),
366: realmPrincipalType.getClass1().trim(),
367: realmPrincipalType.getName().trim());
368: }
369:
370: private static LoginDomainPrincipalInfo buildDomainPrincipal(
371: GerLoginDomainPrincipalType domainPrincipalType) {
372: return new LoginDomainPrincipalInfo(domainPrincipalType
373: .getDomainName().trim(), domainPrincipalType
374: .getClass1().trim(), domainPrincipalType.getName()
375: .trim());
376: }
377:
378: //used from TSSConfigEditor
379: public PrincipalInfo buildPrincipal(XmlObject xmlObject) {
380: GerPrincipalType principalType = (GerPrincipalType) xmlObject;
381: return new PrincipalInfo(principalType.getClass1().trim(),
382: principalType.getName().trim());
383: }
384:
385: protected GBeanData configureRoleMapper(Naming naming,
386: AbstractName moduleName,
387: SecurityConfiguration securityConfiguration) {
388: AbstractName roleMapperName = naming.createChildName(
389: moduleName, "RoleMapper", "RoleMapper");
390: GBeanData roleMapperData = new GBeanData(roleMapperName,
391: ApplicationPrincipalRoleConfigurationManager.GBEAN_INFO);
392: roleMapperData.setAttribute("principalRoleMap",
393: securityConfiguration.getPrincipalRoleMap());
394: return roleMapperData;
395: }
396:
397: protected GBeanData configureApplicationPolicyManager(
398: Naming naming, AbstractName moduleName,
399: Map contextIDToPermissionsMap,
400: SecurityConfiguration securityConfiguration,
401: AbstractNameQuery credentialStoreName) {
402: AbstractName jaccBeanName = naming.createChildName(moduleName,
403: NameFactory.JACC_MANAGER, NameFactory.JACC_MANAGER);
404: GBeanData jaccBeanData = new GBeanData(jaccBeanName,
405: ApplicationPolicyConfigurationManager.GBEAN_INFO);
406: jaccBeanData.setAttribute("contextIdToPermissionsMap",
407: contextIDToPermissionsMap);
408: Map<String, SubjectInfo> roleDesignates = securityConfiguration
409: .getRoleDesignates();
410: jaccBeanData.setAttribute("roleDesignates", roleDesignates);
411: jaccBeanData.setAttribute("defaultSubjectInfo",
412: securityConfiguration.getDefaultSubjectInfo());
413: if ((roleDesignates != null && !roleDesignates.isEmpty())
414: || securityConfiguration.getDefaultSubjectInfo() != null) {
415: jaccBeanData.setReferencePattern("CredentialStore",
416: credentialStoreName);
417: }
418: return jaccBeanData;
419: }
420:
421: public QNameSet getSpecQNameSet() {
422: return QNameSet.EMPTY;
423: }
424:
425: public QNameSet getPlanQNameSet() {
426: return SECURITY_QNAME_SET;
427: }
428:
429: public static final GBeanInfo GBEAN_INFO;
430:
431: static {
432: GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(
433: GeronimoSecurityBuilderImpl.class,
434: NameFactory.MODULE_BUILDER);
435:
436: infoFactory.addAttribute("credentialStoreName",
437: AbstractNameQuery.class, true, true);
438: infoFactory
439: .setConstructor(new String[] { "credentialStoreName" });
440:
441: GBEAN_INFO = infoFactory.getBeanInfo();
442: }
443:
444: public static GBeanInfo getGBeanInfo() {
445: return GBEAN_INFO;
446: }
447:
448: }
|