001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     bstefanescu
016 *
017 * $Id$
018 */
019
020package org.nuxeo.ecm.webengine.security;
021
022import java.text.ParseException;
023import java.util.HashMap;
024import java.util.Map;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028import org.nuxeo.common.xmap.annotation.XContent;
029import org.nuxeo.common.xmap.annotation.XNode;
030import org.nuxeo.common.xmap.annotation.XObject;
031import org.nuxeo.ecm.webengine.security.guards.And;
032import org.nuxeo.ecm.webengine.security.guards.FacetGuard;
033import org.nuxeo.ecm.webengine.security.guards.GroupGuard;
034import org.nuxeo.ecm.webengine.security.guards.IsAdministratorGuard;
035import org.nuxeo.ecm.webengine.security.guards.PermissionGuard;
036import org.nuxeo.ecm.webengine.security.guards.SchemaGuard;
037import org.nuxeo.ecm.webengine.security.guards.ScriptGuard;
038import org.nuxeo.ecm.webengine.security.guards.TypeGuard;
039import org.nuxeo.ecm.webengine.security.guards.UserGuard;
040import org.w3c.dom.DocumentFragment;
041import org.w3c.dom.NamedNodeMap;
042import org.w3c.dom.Node;
043
044/**
045 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
046 */
047@XObject("permission")
048public class GuardDescriptor {
049
050    private static final Log log = LogFactory.getLog(GuardDescriptor.class);
051
052    @XNode("@id")
053    protected String id;
054
055    @XNode("@expression")
056    protected String expression;
057
058    protected Map<String, Guard> guards;
059
060    public GuardDescriptor() {
061        this(null);
062    }
063
064    public GuardDescriptor(String name) {
065        id = name;
066        guards = new HashMap<String, Guard>();
067    }
068
069    public Map<String, Guard> getGuards() {
070        return guards;
071    }
072
073    /**
074     * @param expression the expression to set.
075     */
076    public void setExpression(String expression) {
077        this.expression = expression;
078    }
079
080    /**
081     * @return the expression.
082     */
083    public String getExpression() {
084        return expression;
085    }
086
087    @XContent
088    protected void setGuards(DocumentFragment content) {
089        Node node = content.getFirstChild();
090        while (node != null) {
091            if (node.getNodeType() == Node.ELEMENT_NODE) {
092                String name = node.getNodeName();
093                if ("guard".equals(name)) {
094                    NamedNodeMap map = node.getAttributes();
095                    Node aId = map.getNamedItem("id");
096                    Node aType = map.getNamedItem("type");
097                    if (aId == null) {
098                        throw new IllegalArgumentException("id is required");
099                    }
100                    String id = aId.getNodeValue();
101                    if (aType == null) {
102                        throw new IllegalArgumentException("type is required");
103                    } else {
104                        // String value = node.getTextContent().trim();
105                        // guards.put(id, new ScriptGuard(value));
106                        // TODO: compound guard
107                    }
108                    String type = aType.getNodeValue();
109                    if ("permission".equals(type)) {
110                        String value = node.getTextContent().trim();
111                        guards.put(id, new PermissionGuard(value));
112                    } else if ("isAdministrator".equals(type)) {
113                        String value = node.getTextContent().trim();
114                        guards.put(id, new IsAdministratorGuard(value));
115                    } else if ("facet".equals(type)) {
116                        String value = node.getTextContent().trim();
117                        guards.put(id, new FacetGuard(value));
118                    } else if ("type".equals(type)) {
119                        String value = node.getTextContent().trim();
120                        guards.put(id, new TypeGuard(value));
121                    } else if ("schema".equals(type)) {
122                        String value = node.getTextContent().trim();
123                        guards.put(id, new SchemaGuard(value));
124                    } else if ("user".equals(type)) {
125                        String value = node.getTextContent().trim();
126                        guards.put(id, new UserGuard(value));
127                    } else if ("group".equals(type)) {
128                        String value = node.getTextContent().trim();
129                        guards.put(id, new GroupGuard(value));
130                    } else if ("script".equals(type)) {
131                        Node engineNode = map.getNamedItem("engine");
132                        if (engineNode == null) {
133                            throw new IllegalArgumentException("Must specify an engine attribute on script guards");
134                        }
135                        String value = node.getTextContent().trim();
136                        guards.put(id, new ScriptGuard(engineNode.getNodeValue(), value));
137                    } else if ("expression".equals(type)) {
138                        String value = node.getTextContent().trim();
139                        try {
140                            guards.put(id, PermissionService.getInstance().parse(value, guards));
141                        } catch (ParseException e) {
142                            log.error(e, e);
143                        }
144                    } else { // the type should be a guard factory
145                        String value = node.getTextContent().trim();
146                        try {
147                            Class<?> factory = Class.forName(type);
148                            Guard guard = ((GuardFactory) factory.newInstance()).newGuard(value);
149                            guards.put(id, guard);
150                        } catch (ReflectiveOperationException e) {
151                            log.error(e, e); // TODO should throw a DeployException
152                        }
153                    }
154                }
155            }
156            node = node.getNextSibling();
157        }
158    }
159
160    public Guard getGuard() throws ParseException {
161        if (expression == null || expression.length() == 0) {
162            return new And(guards.values());
163        }
164        return PermissionService.getInstance().parse(expression, guards);
165    }
166
167    public String getId() {
168        return id;
169    }
170
171    public Permission getPermission() throws ParseException {
172        return new DefaultPermission(id, getGuard());
173    }
174
175}