All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openfact.services.security.KeycloakSecurityContextProvider Maven / Gradle / Ivy

The newest version!
package org.openfact.services.security;

import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.representations.AccessToken;
import org.openfact.models.AdminRoles;
import org.openfact.models.OpenfactSession;
import org.openfact.models.OrganizationModel;
import org.openfact.models.OrganizationProvider;
import org.openfact.provider.SingleProviderType;
import org.openfact.services.resource.security.ClientUser;
import org.openfact.services.resource.security.OrganizationAuth;
import org.openfact.services.resource.security.Resource;
import org.openfact.services.resource.security.SecurityContextProvider;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.ForbiddenException;
import java.util.*;
import java.util.stream.Collectors;

@Stateless
@SingleProviderType(provider = "restSecurity", value = "keycloak")
public class KeycloakSecurityContextProvider implements SecurityContextProvider {

    public static final String KEYCLOAK_ORGANIZATION_USER_ATTRIBUTE = "organization";
    public static final String KEYCLOAK_CLIENT = "openfact";

    @Inject
    private OrganizationProvider provider;

    private AccessToken init(OpenfactSession session) {
        HttpServletRequest httpServletRequest = session.getContext().getContextObject(HttpServletRequest.class);
        KeycloakPrincipal kcPrincipal = (KeycloakPrincipal) httpServletRequest.getUserPrincipal();

        if (kcPrincipal != null) {
            return kcPrincipal.getKeycloakSecurityContext().getToken();
        } else {
            throw new IllegalStateException("Could not instantiate KeycloakSecurityContext, check if you installed Keycloak adapter");
        }
    }

    @Override
    public List getPermittedOrganizations(OpenfactSession session) {
        AccessToken accessToken = init(session);
        Collection organizationsName = getPermittedOrganizationNames(accessToken);
        return organizationsName.stream()
                .map(name -> provider.getOrganizationByName(name))
                .collect(Collectors.toList());
    }

    @Override
    public ClientUser getClientUser(OpenfactSession session) {
        AccessToken accessToken = init(session);
        return new ClientUser() {

            @Override
            public String getUsername() {
                return accessToken.getPreferredUsername();
            }

            @Override
            public boolean hasOrganizationRole(String role) {
                return hasRole(role, accessToken);
            }

            @Override
            public boolean hasOneOfOrganizationRole(String... roles) {
                for (String r : roles) {
                    if (hasOrganizationRole(r)) {
                        return true;
                    }
                }
                return false;
            }

            @Override
            public boolean hasAppRole(String role) {
                return hasRole(role, accessToken);
            }

            @Override
            public boolean hasOneOfAppRole(String... roles) {
                for (String r : roles) {
                    if (hasAppRole(r)) {
                        return true;
                    }
                }
                return false;
            }

            @Override
            public OrganizationAuth organizationAuth(Resource resource) {
                return new KeycloakOrganizationAuth(session, resource);
            }
        };
    }

    private Collection getPermittedOrganizationNames(AccessToken accessToken) {
        Map otherClaims = accessToken.getOtherClaims();
        if (otherClaims.containsKey(KEYCLOAK_ORGANIZATION_USER_ATTRIBUTE)) {
            Object object = otherClaims.get(KEYCLOAK_ORGANIZATION_USER_ATTRIBUTE);
            if (object instanceof Collection) {
                return (Collection) object;
            } else {
                return Arrays.asList((String) object);
            }
        }
        return Collections.EMPTY_LIST;
    }

    private boolean hasRole(String role, AccessToken accessToken) {
        Set organizationRoles = accessToken.getRealmAccess().getRoles();
        AccessToken.Access resourceAccess = accessToken.getResourceAccess(KEYCLOAK_CLIENT);
        Set applicationRoles = resourceAccess != null ? resourceAccess.getRoles() : Collections.emptySet();
        return organizationRoles.contains(role) || applicationRoles.contains(role);
    }

    public class KeycloakOrganizationAuth implements OrganizationAuth {

        private OpenfactSession session;
        private Resource resource;

        public KeycloakOrganizationAuth(OpenfactSession session, Resource resource) {
            this.session = session;
            this.resource = resource;
        }

        @Override
        public void init(Resource resource) {
            this.resource = resource;
        }

        @Override
        public void requireAny() {
            if (!getClientUser(session).hasOneOfAppRole(AdminRoles.ALL_ORGANIZATION_ROLES)) {
                throw new ForbiddenException();
            }
        }

        @Override
        public boolean hasView() {
            return getClientUser(session).hasOneOfAppRole(AdminRoles.getViewRole(resource), AdminRoles.getManageRole(resource));
        }

        @Override
        public boolean hasManage() {
            return getClientUser(session).hasOneOfAppRole(AdminRoles.getManageRole(resource));
        }

        @Override
        public void requireView() {
            if (!hasView()) {
                throw new ForbiddenException();
            }
        }

        @Override
        public void requireManage() {
            if (!hasManage()) {
                throw new ForbiddenException();
            }
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy