001package com.identityworksllc.iiq.common;
002
003import com.identityworksllc.iiq.common.auth.DummyAuthContext;
004import sailpoint.api.SailPointContext;
005import sailpoint.authorization.LcmRequestAuthorizer;
006import sailpoint.authorization.QuickLinkLaunchAuthorizer;
007import sailpoint.authorization.UnauthorizedAccessException;
008import sailpoint.object.Identity;
009import sailpoint.object.Identity.CapabilityManager;
010import sailpoint.object.QuickLink;
011import sailpoint.tools.GeneralException;
012
013import java.util.Objects;
014
015/**
016 * Utilities for authorization, e.g., whether a user can view a QuickLink. For the
017 * Common Security style of authorization, use ThingAccessUtils instead.
018 */
019public class AuthUtilities extends AbstractBaseUtility {
020
021        /**
022         * Indicates the type of access to a QuickLink we are checking
023         */
024        public enum QuickLinkAccessType {
025                /**
026                 * Check ANY type of access (self or other)
027                 */
028                ANY,
029                /**
030                 * Check whether this user can invoke this QuickLink on other users
031                 */
032                OTHER,
033                /**
034                 * Check whether this user can invoke this QuickLink on themselves
035                 */
036                SELF
037        }
038
039        /**
040         * Constructs a new instance of AuthUtilities
041         * @param c
042         */
043        public AuthUtilities(SailPointContext c) {
044                super(c);
045        }
046
047        /**
048         * Returns true if the given person could launch the given QuickLink against the given target.
049         *
050         * You may pass a null target or a target the same as the launcher to infer an access type of
051         * SELF. If the target is not null and does not match the launcher, an access type of OTHER
052         * will be inferred.
053         *
054         * @param launcher The person we're testing for access
055         * @param target The (optional) target against whom the QuickLink would be executed
056         * @param what The QuickLink we're testing
057         * @return true if the launcher could perform this QL operation
058         * @throws GeneralException if any IIQ failure occurs
059         */
060        public boolean canAccessQuicklink(Identity launcher, Identity target, QuickLink what) throws GeneralException {
061                Objects.requireNonNull(launcher, "The 'launcher' Identity must not be null");
062                if (target == null || target.getId().equals(launcher.getId())) {
063                        return canAccessQuicklink(launcher, launcher, what, QuickLinkAccessType.SELF);
064                } else {
065                        return canAccessQuicklink(launcher, target, what, QuickLinkAccessType.SELF);
066                }
067        }
068
069        /**
070         * Returns true if the given person could launch the given QuickLink against the given target. Pass a
071         * null target to take the QuickLinkAccessType into account, e.g. if you just need a general "can see
072         * in any circumstance" answer.
073         * 
074         * @param launcher The person we're testing for access
075         * @param target The (optional) target against whom the QuickLink would be executed
076         * @param what The QuickLink we're testing
077         * @param accessType The access type we're interested in
078         * @return true if the launcher could perform this QL operation
079         * @throws GeneralException if any IIQ failure occurs
080         */
081        public boolean canAccessQuicklink(Identity launcher, Identity target, QuickLink what, QuickLinkAccessType accessType) throws GeneralException {
082                Objects.requireNonNull(launcher, "The 'launcher' Identity must not be null");
083                DummyAuthContext authContext = new DummyAuthContext(context, launcher.getName());
084                if (accessType == QuickLinkAccessType.ANY) {
085                        return canViewQuicklink(launcher, what, accessType);
086                } else {
087                        String lcmAction = null;
088                        if (!(what.getAction().equals(QuickLink.ACTION_WORKFLOW) || what.getAction().equals(QuickLink.ACTION_EXTERNAL))) {
089                                lcmAction = what.getAction();
090                        }
091                        if (target == null && accessType == QuickLinkAccessType.SELF) {
092                                target = launcher;
093                        }
094                        LcmRequestAuthorizer authorizer = new LcmRequestAuthorizer(target);
095                        authorizer.setQuickLinkName(what.getName());
096                        authorizer.setAction(lcmAction);
097                        try {
098                                authorizer.authorize(authContext);
099                                return true;
100                        } catch(UnauthorizedAccessException e) {
101                                return false;
102                        }
103                }
104        }
105
106        /**
107         * Returns true if the user in question can view the QuickLink under any circumstances (i.e. if it would be displayed on their sidebar).
108         * @param launcher The user to query
109         * @param what The QuickLink to check
110         * @param accessType The access type to check for
111         * @return If the user would have access to this QuickLink, true, otherwise false
112         * @throws GeneralException if any IIQ failure occurs
113         */
114        public boolean canViewQuicklink(Identity launcher, QuickLink what, QuickLinkAccessType accessType) throws GeneralException {
115                DummyAuthContext authContext = new DummyAuthContext(context, launcher.getName());
116                try {
117                        QuickLinkLaunchAuthorizer authorizer = new QuickLinkLaunchAuthorizer(what, accessType == QuickLinkAccessType.ANY || accessType == QuickLinkAccessType.SELF);
118                        authorizer.authorize(authContext);
119                        return true;
120                } catch(UnauthorizedAccessException e) {
121                        if (accessType == QuickLinkAccessType.ANY) {
122                                try {
123                                        QuickLinkLaunchAuthorizer authorizer = new QuickLinkLaunchAuthorizer(what, false);
124                                        authorizer.authorize(authContext);
125                                        return true;
126                                } catch(UnauthorizedAccessException e2) {
127                                        return false;
128                                }
129                        }
130                        return false;
131                }
132        }
133        
134        /**
135         * Throws an exception if the given Identity does not have the given right (optionally
136         * also allowing sysadmins).
137         * 
138         * @param who The identity to test
139         * @param what The SPRight to test for
140         * @param allowAdmins If true, SystemAdministrators will also be allowed, even without the SPRight
141         * @throws UnauthorizedAccessException if the user does not have access
142         */
143        public void checkAuthorization(Identity who, String what, boolean allowAdmins) throws UnauthorizedAccessException {
144                boolean allowed = false;
145                CapabilityManager cm = who.getCapabilityManager();
146                if (allowAdmins) {
147                        allowed = cm.hasCapability("SystemAdministrator");
148                }
149                if (!allowed) {
150                        allowed = cm.hasRight(what);
151                }
152                if (!allowed) {
153                        throw new UnauthorizedAccessException("Access to this resource requires SPRight " + what);
154                }
155        }
156        
157}