001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.sec.document;
017    
018    import java.util.Iterator;
019    import java.util.Map;
020    
021    import org.apache.commons.lang.StringUtils;
022    import org.kuali.kfs.sec.SecConstants;
023    import org.kuali.kfs.sec.businessobject.SecurityDefinition;
024    import org.kuali.kfs.sec.businessobject.SecurityModelMember;
025    import org.kuali.kfs.sec.businessobject.SecurityPrincipal;
026    import org.kuali.kfs.sec.businessobject.SecurityPrincipalDefinition;
027    import org.kuali.kfs.sec.identity.SecKimAttributes;
028    import org.kuali.kfs.sec.util.KimUtil;
029    import org.kuali.kfs.sys.context.SpringContext;
030    import org.kuali.kfs.sys.document.FinancialSystemMaintainable;
031    import org.kuali.rice.kew.exception.WorkflowException;
032    import org.kuali.rice.kim.bo.role.dto.KimRoleInfo;
033    import org.kuali.rice.kim.bo.role.dto.RoleMembershipInfo;
034    import org.kuali.rice.kim.bo.types.dto.AttributeSet;
035    import org.kuali.rice.kim.service.IdentityManagementService;
036    import org.kuali.rice.kim.service.RoleManagementService;
037    import org.kuali.rice.kim.util.KimConstants;
038    import org.kuali.rice.kns.bo.DocumentHeader;
039    import org.kuali.rice.kns.bo.PersistableBusinessObject;
040    import org.kuali.rice.kns.document.MaintenanceDocument;
041    import org.kuali.rice.kns.service.DocumentService;
042    import org.kuali.rice.kns.util.KNSConstants;
043    
044    
045    /**
046     * Maintainable implementation for the Security Principal maintenance document. Hooks into Post processing to create the KIM permissions for the principal and assign security role
047     * members
048     */
049    public class SecurityPrincipalMaintainableImpl extends FinancialSystemMaintainable {
050        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SecurityPrincipalMaintainableImpl.class);
051    
052        /**
053         * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#refresh(java.lang.String, java.util.Map, org.kuali.rice.kns.document.MaintenanceDocument)
054         */
055        @Override
056        public void refresh(String refreshCaller, Map fieldValues, MaintenanceDocument document) {
057            super.refresh(refreshCaller, fieldValues, document);
058    
059            this.getBusinessObject().refreshNonUpdateableReferences();
060            for (Iterator iterator = newCollectionLines.values().iterator(); iterator.hasNext();) {
061                PersistableBusinessObject businessObject = (PersistableBusinessObject) iterator.next();
062                businessObject.refreshNonUpdateableReferences();
063            }
064        }
065    
066        /**
067         * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#doRouteStatusChange(org.kuali.rice.kns.bo.DocumentHeader)
068         */
069        @Override
070        public void doRouteStatusChange(DocumentHeader documentHeader) {
071            super.doRouteStatusChange(documentHeader);
072    
073            if (documentHeader.getWorkflowDocument().stateIsProcessed()) {
074                DocumentService documentService = SpringContext.getBean(DocumentService.class);
075                try {
076                    MaintenanceDocument document = (MaintenanceDocument) documentService.getByDocumentHeaderId(documentHeader.getDocumentNumber());
077                    SecurityPrincipal oldSecurityPrincipal = (SecurityPrincipal) document.getOldMaintainableObject().getBusinessObject();
078                    SecurityPrincipal newSecurityPrincipal = (SecurityPrincipal) document.getNewMaintainableObject().getBusinessObject();
079    
080                    boolean newMaintenanceAction = getMaintenanceAction().equalsIgnoreCase(KNSConstants.MAINTENANCE_NEW_ACTION) || getMaintenanceAction().equalsIgnoreCase(KNSConstants.MAINTENANCE_COPY_ACTION);
081    
082                    assignOrUpdatePrincipalMembershipToDefinitionRoles(oldSecurityPrincipal, newSecurityPrincipal, newMaintenanceAction);
083                    assignOrUpdatePrincipalModelRoles(newSecurityPrincipal);
084                    
085                    SpringContext.getBean(IdentityManagementService.class).flushAllCaches();
086                }
087                catch (WorkflowException e) {
088                    LOG.error("caught exception while handling handleRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
089                    throw new RuntimeException("caught exception while handling handleRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
090                }
091            }
092        }
093    
094        /**
095         * Iterates through the principal definition list and assigns the principal to the definition role if necessary or updates the current member assignment
096         * 
097         * @param oldSecurityPrincipal SecurityPrincipal before updates
098         * @param newSecurityPrincipal SecurityPrincipal which contains the definition list and principal
099         * @param newMaintenanceAction boolean indicating whether this is a new record (old side will not contain data)
100         */
101        protected void assignOrUpdatePrincipalMembershipToDefinitionRoles(SecurityPrincipal oldSecurityPrincipal, SecurityPrincipal newSecurityPrincipal, boolean newMaintenanceAction) {
102            RoleManagementService roleService = SpringContext.getBean(RoleManagementService.class);
103    
104            String principalId = newSecurityPrincipal.getPrincipalId();
105    
106            for (SecurityPrincipalDefinition securityPrincipalDefinition : newSecurityPrincipal.getPrincipalDefinitions()) {
107                SecurityDefinition securityDefinition = securityPrincipalDefinition.getSecurityDefinition();
108    
109                KimRoleInfo definitionRoleInfo = roleService.getRole(securityDefinition.getRoleId());
110                
111                RoleMembershipInfo principalMembershipInfo = null;
112                if (!newMaintenanceAction) {
113                    SecurityPrincipalDefinition oldPrincipalDefinition = null;
114                    for (SecurityPrincipalDefinition principalDefinition : oldSecurityPrincipal.getPrincipalDefinitions()) {
115                       if ((principalDefinition.getPrincipalDefinitionId() != null) && principalDefinition.getPrincipalDefinitionId().equals(securityPrincipalDefinition.getPrincipalDefinitionId())) {
116                           oldPrincipalDefinition = principalDefinition;
117                       }
118                    }
119                    
120                    if (oldPrincipalDefinition != null) {
121                        AttributeSet membershipQualifications = new AttributeSet();
122                        membershipQualifications.put(SecKimAttributes.CONSTRAINT_CODE, oldPrincipalDefinition.getConstraintCode());
123                        membershipQualifications.put(SecKimAttributes.OPERATOR, oldPrincipalDefinition.getOperatorCode());
124                        membershipQualifications.put(SecKimAttributes.PROPERTY_VALUE, oldPrincipalDefinition.getAttributeValue());
125                        membershipQualifications.put(SecKimAttributes.OVERRIDE_DENY, Boolean.toString(oldPrincipalDefinition.isOverrideDeny()));
126    
127                        principalMembershipInfo = KimUtil.getRoleMembershipInfoForMemberType(definitionRoleInfo.getRoleId(), principalId, KimConstants.KimUIConstants.MEMBER_TYPE_PRINCIPAL_CODE, membershipQualifications);
128                    }
129                }
130    
131                // only create membership if principal definition record is active
132                boolean membershipActive = securityPrincipalDefinition.isActive();
133    
134                // if membership already exists, need to remove if the principal record is now inactive or the qualifications need updated
135                String principalMembershipId = "";
136                if (principalMembershipInfo != null) {
137                    principalMembershipId = principalMembershipInfo.getRoleMemberId();
138                    boolean qualificationsMatch = KimUtil.doMembershipQualificationsMatchValues(principalMembershipInfo.getQualifier(), securityPrincipalDefinition.getConstraintCode(), securityPrincipalDefinition.getOperatorCode(), securityPrincipalDefinition.getAttributeValue());
139                    if (!membershipActive || !qualificationsMatch) {
140                        roleService.removeRoleFromRole(principalMembershipInfo.getMemberId(), definitionRoleInfo.getNamespaceCode(), definitionRoleInfo.getRoleName(), principalMembershipInfo.getQualifier());
141                    }
142                }
143    
144                // create of update role if membership should be active
145                if (membershipActive) {
146                    AttributeSet membershipQualifications = new AttributeSet();
147                    membershipQualifications.put(SecKimAttributes.CONSTRAINT_CODE, securityPrincipalDefinition.getConstraintCode());
148                    membershipQualifications.put(SecKimAttributes.OPERATOR, securityPrincipalDefinition.getOperatorCode());
149                    membershipQualifications.put(SecKimAttributes.PROPERTY_VALUE, securityPrincipalDefinition.getAttributeValue());
150                    membershipQualifications.put(SecKimAttributes.OVERRIDE_DENY, Boolean.toString(securityPrincipalDefinition.isOverrideDeny()));
151    
152                    roleService.saveRoleMemberForRole(principalMembershipId, principalId, KimConstants.KimUIConstants.MEMBER_TYPE_PRINCIPAL_CODE, definitionRoleInfo.getRoleId(), membershipQualifications, null, null);
153                }
154            }
155        }
156    
157        /**
158         * Iterates through the principal model list and assigns the principal to the model role or updates the membership
159         * 
160         * @param securityPrincipal SecurityPrincipal which contains the model list and principal
161         */
162        protected void assignOrUpdatePrincipalModelRoles(SecurityPrincipal securityPrincipal) {
163            RoleManagementService roleService = SpringContext.getBean(RoleManagementService.class);
164    
165            String principalId = securityPrincipal.getPrincipalId();
166    
167            for (SecurityModelMember principalModel : securityPrincipal.getPrincipalModels()) {
168                KimRoleInfo modelRoleInfo = roleService.getRole(principalModel.getSecurityModel().getRoleId());
169    
170                RoleMembershipInfo membershipInfo = KimUtil.getRoleMembershipInfoForMemberType(modelRoleInfo.getRoleId(), principalId, KimConstants.KimUIConstants.MEMBER_TYPE_PRINCIPAL_CODE, null);
171    
172                String membershipId = "";
173                if (membershipInfo != null) {
174                    membershipId = membershipInfo.getRoleMemberId();
175                }
176    
177                java.sql.Date fromDate = null;
178                java.sql.Date toDate = null;
179                if ( principalModel.getActiveFromDate() != null ) {
180                    fromDate = new java.sql.Date( principalModel.getActiveFromDate().getTime() ); 
181                }
182                if ( principalModel.getActiveToDate() != null ) {
183                    toDate = new java.sql.Date( principalModel.getActiveToDate().getTime() ); 
184                }
185                roleService.saveRoleMemberForRole(membershipId, principalId, KimConstants.KimUIConstants.MEMBER_TYPE_PRINCIPAL_CODE, modelRoleInfo.getRoleId(), new AttributeSet(), fromDate, toDate);
186            }
187        }
188    
189    }