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

com.day.cq.security.util.AuthorizableJSONWriter Maven / Gradle / Ivy

/*
 * Copyright 1997-2008 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.security.util;

import java.io.Writer;
import java.security.Principal;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;

import com.adobe.granite.security.user.UserProperties;
import com.adobe.granite.security.user.UserPropertiesManager;
import com.adobe.granite.security.user.UserPropertiesService;
import com.day.cq.commons.JSONWriterUtil;
import com.day.cq.replication.ReplicationQueue;
import com.day.cq.replication.ReplicationStatus;
import com.day.cq.security.profile.ProfileManager;
import com.day.cq.xss.XSSProtectionService;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.io.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.day.cq.commons.jcr.JcrConstants.JCR_CONTENT;
import static com.day.cq.commons.jcr.JcrConstants.JCR_CREATED;
import static com.day.cq.commons.jcr.JcrConstants.JCR_CREATED_BY;
import static com.day.cq.commons.jcr.JcrConstants.JCR_LASTMODIFIED;

/**
 * Little writer knowing some of the Authorizables special cases that do not
 * compile a Bean-convention
 *
 * @deprecated cq 5.5 Use platform functionality instead.
 */
public class AuthorizableJSONWriter {

    /**
     * Maps user property names to profile properties. This is only needed
     * for backward compatibility reasons. See bug# 26797.
     */
    private static final Map USER_TO_PROFILE_PROPS;

    static {
        Map tmp = new HashMap();
        tmp.put(com.day.cq.security.Authorizable.PROPERTY_DESCRIPTION, UserProperties.ABOUT_ME);
        tmp.put(com.day.cq.security.Authorizable.PROPERTY_EMAIL, UserProperties.EMAIL);
        tmp.put(com.day.cq.security.Authorizable.PROPERTY_FIRST_NAME, UserProperties.GIVEN_NAME);
        tmp.put(com.day.cq.security.Authorizable.PROPERTY_LAST_NAME, UserProperties.FAMILY_NAME);
        USER_TO_PROFILE_PROPS = tmp;
    }

    private final static Logger log = LoggerFactory.getLogger(AuthorizableJSONWriter.class);

    public static final String GROUP = "group";

    public static final String USER = "user";

    public static final String KEY_HOME_PATH = "home";

    private final ResourceResolver resourceResolver;
    private final Session session;

    private final UserPropertiesManager pMgr;

    private Set outputProps;

    private XSSProtectionService xss;

    private boolean basic;

    private int membersLimit = -1;

    /**
     * Creates a default authorizable writer.
     */
    public AuthorizableJSONWriter() {
        throw new UnsupportedOperationException("No longer supported (AuthorizableJSONWriter())");
    }

    /**
     * todo
     * @param pMgr the profile manager
     * @param session the session
     * @param outputProps the output properties
     * @param xss the XSS protection service
     * @since 5.4
     */
    public AuthorizableJSONWriter(ProfileManager pMgr, Session session, String[] outputProps, XSSProtectionService xss) {
        throw new UnsupportedOperationException("No longer supported (AuthorizableJSONWriter(ProfileManager, Sesion, String[], XSSProtectionService))");
    }

    public AuthorizableJSONWriter(ResourceResolver resourceResolver, UserPropertiesManager pMgr, String[] outputProps, XSSProtectionService xss) {
        this.resourceResolver = resourceResolver;
        this.session = (resourceResolver == null) ? null : resourceResolver.adaptTo(Session.class);
        this.pMgr = pMgr;
        setOutputProps(outputProps);
        this.xss = xss;
    }

    /**
     * Sets the members limit.
     * @param membersLimit the limit
     */
    public void setMembersLimit(int membersLimit) {
        this.membersLimit = membersLimit;
    }

    /**
     * Set the properties that will be present in the output.
     * @param outputProps the output properties
     * @since 5.4
     */
    public void setOutputProps(String[] outputProps) {
        if (outputProps == null) {
            this.outputProps = null;
        }
        else {
            this.outputProps = new HashSet();
            for (String p : outputProps) {
                this.outputProps.add(p);
            }
        }
    }

    /**
     * Define if only basic information should be written
     * @param basic true to only dump basic information
     */
    public void setBasic(boolean basic) {
        this.basic = basic;
    }

    /**
     * Set XSS protection service to use to prevent from XSS attacks
     *
     * @param xss
     * @since 5.4
     */
    public void setXss(XSSProtectionService xss) {
        this.xss = xss;
    }

    public void write(JSONWriter writer, com.day.cq.security.Authorizable authorizable) throws JSONException {
        throw new UnsupportedOperationException("No longer supported (AuthorizableJSONWriter#write(JsonWriter,Authorizable)");
    }

    public void write(JSONWriter writer, Authorizable authorizable) throws JSONException, RepositoryException {
        writer.object();
        UserProperties profile = getProfile(authorizable);
        if (!basic) {
            // write profile properties first, so they do not overwrite the
            // 'real' user properties (see CQ-7755)
            Map profileProps = new HashMap();
            // 1) use mapping from user properties to profile
            //    as defined in CQ 5.2.1
            // see bug# 26797
            for (Map.Entry entry : USER_TO_PROFILE_PROPS.entrySet()) {
                String userPropName = entry.getKey();
                String profPropName = entry.getValue();
                Value[] value = authorizable.getProperty(userPropName);
                if (value != null && value.length > 0) {
                    profileProps.put(profPropName, value[0].getString());
                }
            }
            // 2) overlay with real profile properties
            if (profile != null) {
                for (String name : profile.getPropertyNames()) {
                    profileProps.put(name, profile.getProperty(name));
                }
            }
            // 3) write out props
            for (Map.Entry entry : profileProps.entrySet()) {
                JSONWriterUtil.write(writer, entry.getKey(), entry.getValue(), JSONWriterUtil.WriteMode.BOTH, xss);
            }

            Node authorizableNode = session.getNode(authorizable.getPath());
            try {
                write(writer, JCR_CREATED, authorizableNode.getProperty(JCR_CREATED).getString());
            } catch (RepositoryException e) {
                log.warn("Unable to get {} property from authorizable {}", JCR_CREATED, authorizable.getPath());
            }
            try {
                write(writer, JCR_CREATED_BY, authorizableNode.getProperty(JCR_CREATED_BY).getString());
            } catch (RepositoryException e) {
                log.warn("Unable to get {} property from authorizable {}", JCR_CREATED_BY, authorizable.getPath());
            }

            write(writer, "principal", authorizable.getPrincipal().getName());
            writeAuthorizables(writer, "memberOf", authorizable.declaredMemberOf(), -1, JSONWriterUtil.WriteMode.BOTH);

            if (!authorizable.isGroup()) {
                write(writer, "rep:userId", authorizable.getID());
                User user = (User) authorizable;
                PrincipalIterator impersonators = user.getImpersonation().getImpersonators();
                Set impAuthorizables = new HashSet();
                UserManager userMgr = ((JackrabbitSession) session).getUserManager();
                while (impersonators.hasNext()) {
                    Principal p = impersonators.nextPrincipal();
                    Authorizable a = userMgr.getAuthorizable(p);
                    if (p != null && a!=null) {
                        impAuthorizables.add(a);
                    }
                }
                writeAuthorizables(writer, "sudoers", impAuthorizables.iterator(), -1, JSONWriterUtil.WriteMode.BOTH);
                try {
                    if (user.isDisabled()) {
                        write(writer, "disabled", user.getDisabledReason());
                    }
                } catch (RepositoryException e) {
                    throw new JSONException(e);
                }
            } else {
                write(writer, "groupName", authorizable.getID());
                Iterator memberIter = null;
                if (membersLimit == 0) {
                    memberIter = Collections.emptyList().iterator();
                } else {
                    memberIter = ((Group) authorizable).getDeclaredMembers();
                }
                writeAuthorizables(writer, "members", memberIter, membersLimit, JSONWriterUtil.WriteMode.BOTH);
            }

            // the regular properties on the authorizable
            Iterator itr = authorizable.getPropertyNames();
            while(itr.hasNext()) {
                String name = itr.next();
                if ("id".equals(name) || "name".equals(name)) {
                    continue;
                }
                Value[] vs = authorizable.getProperty(name);
                if (vs != null && vs.length > 0) {
                    write(writer, name, vs[0].getString());

                }
            }

            // profile pic
            Resource primPhoto = null;
            if (profile != null) {
                Iterator photos = profile.getResources("photos");
                while(photos.hasNext()) {
                    primPhoto = photos.next();
                    break;
                    // todo (primary check seems currently not to work)
                    // taken from foundation/components/profile/form/avatar/avatar.jsp
//                    Resource check = photos.next();
//                    if (check.adaptTo(ValueMap.class).get("primary", false)) {
//                        writer.value("checked");
//                        primPhoto = check;
//                        break;
//                    }
                }
            }

            if (primPhoto != null) {
                Node photoNode = primPhoto.adaptTo(Node.class);
                String ext = "png";
                long ck = 0;
                try {
                    Node content = photoNode.getNode("image").getNode(JCR_CONTENT);
                    // build cache killer from modification date of thumbnail
                    ck = content.getProperty(JCR_LASTMODIFIED).getLong();
                    // remove milliseconds in order to match the mod date provided by json servlets
                    ck = ck / 1000 * 1000;
                    // currently always PNG because of transparency
//                    ext = ImageHelper.getExtensionFromType(content.getProperty("jcr:mimeType").getString());
                }
                catch (PathNotFoundException e) {
                    // use default
                }
                catch (RepositoryException e) {
                    // use default
                }

//                write(writer, "thumbnailPath", primPhoto.getPath() + "/image.prof.thumbnail." + ext + "/" + ck + "." + ext);
                write(writer, "picturePath", primPhoto.getPath());
                write(writer, "pictureExt", ext);
                write(writer, "pictureMod", ck);
            }
            else {
                write(writer, "thumbnail", "");
            }

            writeModificationDates(writer, authorizable);
            writeReplication(writer, authorizable);
        }
        write(writer, "type", authorizable.isGroup() ? GROUP : USER);

        //don't use key map, as the covenantee does not reflect bean convention
        JSONWriterUtil.write(writer, "id", authorizable.getID(), JSONWriterUtil.WriteMode.BOTH, xss);
        JSONWriterUtil.write(writer, "name", getName(authorizable, profile), JSONWriterUtil.WriteMode.BOTH, xss);
        write(writer, KEY_HOME_PATH, authorizable.getPath());

        writer.endObject();
    }

    public void write(Writer out, com.day.cq.security.Authorizable authorizable) throws JSONException {
        throw new UnsupportedOperationException("No longer supported (AuthorizableJSONWriter#write(Writer,com.day.cq.security.Authorizable)");
    }

    public void write(Writer out, Authorizable authorizable) throws JSONException, RepositoryException {
        write(new JSONWriter(out), authorizable);
    }

    public void writeTable(Writer out, com.day.cq.security.Authorizable authorizable) throws JSONException, RepositoryException {
        throw new UnsupportedOperationException("No longer supported (AuthorizableJSONWriter#write(Writer,com.day.cq.security.Authorizable)");
    }

    public void writeTable(Writer out, Authorizable authorizable) throws JSONException, RepositoryException {
        JSONWriter writer = new JSONWriter(out);
        writer.object();
        writeColumnHeader(writer, authorizable);
        writeRows(writer, authorizable);
        writer.endObject();
    }

    private void write(JSONWriter writer, String key, String value) throws JSONException {
        if (includeKey(key)) {
            JSONWriterUtil.write(writer, key, value, null, xss);
        }
    }

    private void write(JSONWriter writer, String key, long value) throws JSONException {
        if (includeKey(key)) {
            writer.key(key).value(value);
        }
    }

    private void writeRows(JSONWriter json, Authorizable authorizable) throws JSONException, RepositoryException {
        json.key("rows");
        json.array();

        UserProperties profile = getProfile(authorizable);
        //--------------------------
        json.array();
        json.value(authorizable.getID());
        json.array();
        json.value(getName(authorizable, profile));
        if (!authorizable.isGroup()) {
            json.value(authorizable.getID());
            json.value("***");
        }
        if (profile != null) {
            json.value(profile.getProperty(UserProperties.EMAIL));
        }
        json.endArray();
        json.endArray();
        //--------------------------
        json.endArray();
    }

    private static void writeColumnHeader(JSONWriter json, Authorizable authorizable) throws JSONException {
        json.key("columns");
        json.array();
        json.object();
        json.key("id").value("name");
        json.key("text").value("Name");
        json.endObject();
        if (!authorizable.isGroup()) {
            json.object();
            json.key("id").value("rep:userId");
            json.key("text").value("User-ID");
            json.key("inputWidget");
            json.object();
            json.key("type").value("CqTextBox");
            json.endObject();

            json.endObject();
            json.object();
            json.key("id").value("password");
            json.key("text").value("Password");
            json.endObject();
        }
        json.object();
        json.key("id").value("email");
        json.key("text").value("Email");
        json.endObject();
        json.endArray();
    }

    private void writeAuthorizables(JSONWriter writer, String key, Iterator auths, int limit, JSONWriterUtil.WriteMode writeMode)
            throws JSONException, RepositoryException {

        if (includeKey(key)) {
            writer.key(key);
            writer.array();
        }

        int count = 0;
        while (auths.hasNext() && (limit == -1 || count < limit)) {
            Authorizable auth = auths.next();
            if (includeKey(key)) {
                writer.object();
                writer.key("id").value(auth.getID());
                JSONWriterUtil.write(writer, "name", getName(auth, getProfile(auth)), writeMode, xss);
                writer.key("home").value(auth.getPath());
                writer.endObject();
            }
            count++;
        }

        if (includeKey(key)) {
            writer.endArray();
        }

        if (includeKey(key + "Total")) {
            writer.key(key + "Total").value(count);
        }
    }

    private void writeModificationDates(JSONWriter writer, Authorizable authorizable) throws JSONException, RepositoryException {
        if (includeKey("modification")) {
            writer.key("modification").object();
            Calendar lastMod = null;
            if (authorizable.hasProperty("cq:lastModified")) {
                lastMod = authorizable.getProperty("cq:lastModified")[0].getDate();
            }
            if (lastMod!=null) {
                writer.key("lastModified").value(lastMod.getTimeInMillis());
                String lastModifiedBy = null;
                if (authorizable.hasProperty("cq:lastModifiedBy")) {
                    lastModifiedBy = authorizable.getProperty("cq:lastModifiedBy")[0].getString();
                }
                JSONWriterUtil.write(writer, "lastModifiedBy", getFormattedName(lastModifiedBy), JSONWriterUtil.WriteMode.BOTH, xss);
            }
            writer.endObject();
        }
    }

    private void writeReplication(JSONWriter writer, Authorizable authorizable) throws JSONException, RepositoryException {
        if (includeKey("replication")) {
            Resource authorizableResource = resourceResolver.getResource(authorizable.getPath());
            if (authorizableResource != null) {
                ReplicationStatus replicationStatus = authorizableResource.adaptTo(ReplicationStatus.class);
                writer.key("replication").object();
                if (replicationStatus != null) {
                    int maxQueuePos = -1;
                    for (ReplicationQueue.Entry e : replicationStatus.getPending()) {
                        if (e.getQueuePosition() > maxQueuePos) {
                            maxQueuePos = e.getQueuePosition();
                        }
                    }
                    writer.key("numQueued").value(maxQueuePos+1);
                    Calendar last = replicationStatus.getLastPublished();
                    if (last != null) {
                        writer.key("published").value(last.getTimeInMillis());
                        JSONWriterUtil.write(writer, "publishedBy", getFormattedName(replicationStatus.getLastPublishedBy()), JSONWriterUtil.WriteMode.BOTH, xss);
                        if (replicationStatus.getLastReplicationAction() != null) {
                            writer.key("action").value(replicationStatus.getLastReplicationAction().name());
                        }
                    }
                }
                writer.endObject();
            }
        }
    }

    private UserProperties getProfile(Authorizable authorizable) throws RepositoryException {
        return (pMgr != null) ? pMgr.getUserProperties(authorizable, UserPropertiesService.PROFILE_PATH) : null;
    }

    private String getFormattedName(String id) {
        if (id != null && pMgr != null) {
            try {
                UserProperties profile = pMgr.getUserProperties(id, UserPropertiesService.PROFILE_PATH);
                if (profile != null) {
                    String name = profile.getDisplayName();
                    if (name != null && name.length() > 0) {
                        id = name;
                    }
                }
            } catch (RepositoryException e) {
                log.debug("Could not access Repository, when trying to access full name of {}: {}",
                        id, e);
            }
        }
        return id;
    }

    /**
     * Backwards compatible with CQ Authorizable#getName
     * @param authorizable
     * @return
     */
    private static String getName(Authorizable authorizable, UserProperties profile) throws RepositoryException {
        String name = null;
        if (profile != null) {
            if (authorizable.isGroup()) {
                name = profile.getProperty(UserProperties.GIVEN_NAME);
            } else {
                name = profile.getDisplayName();
            }
        }
        return (name != null && !name.isEmpty()) ? name : authorizable.getID();
    }

    private boolean includeKey(String key) {
        if (outputProps == null) {
            return true;
        }
        else if (outputProps.contains("*")) {
            return !outputProps.contains(key);
        }
        else {
            return outputProps.contains(key);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy