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