001    /*
002     * 
003     * $Revision: 15202 $ $Date: 2009-05-15 17:00:44 +0200 (Fri, 15 May 2009) $
004     *
005     * This file is part of ***  M y C o R e  ***
006     * See http://www.mycore.de/ for details.
007     *
008     * This program is free software; you can use it, redistribute it
009     * and / or modify it under the terms of the GNU General Public License
010     * (GPL) as published by the Free Software Foundation; either version 2
011     * of the License or (at your option) any later version.
012     *
013     * This program is distributed in the hope that it will be useful, but
014     * WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program, in a file called gpl.txt or license.txt.
020     * If not, write to the Free Software Foundation Inc.,
021     * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
022     */
023    
024    package org.mycore.frontend.servlets;
025    
026    import java.io.InputStream;
027    import java.net.URL;
028    import java.util.ArrayList;
029    import java.util.Collection;
030    import java.util.List;
031    
032    import org.apache.log4j.Logger;
033    import org.jdom.Element;
034    import org.mycore.access.MCRAccessManager;
035    import org.mycore.common.MCRConfiguration;
036    import org.mycore.common.MCRConfigurationException;
037    import org.mycore.common.MCRException;
038    import org.mycore.common.MCRSession;
039    import org.mycore.common.MCRSessionMgr;
040    import org.mycore.datamodel.common.MCRActiveLinkException;
041    import org.mycore.datamodel.metadata.MCRObjectID;
042    import org.mycore.datamodel.metadata.MCRObjectService;
043    import org.mycore.frontend.editor.MCREditorSubmission;
044    import org.mycore.frontend.editor.MCRRequestParameters;
045    import org.mycore.user.MCRUserMgr;
046    
047    /**
048     * The servlet store the MCREditorServlet output XML in a file of a MCR type
049     * dependencies directory, check it dependence of the MCR type and store the XML
050     * in a file in this directory or if an error was occured start the editor again
051     * with <b>todo </b> <em>repair</em>.
052     * 
053     * @author Jens Kupferschmidt
054     * @author Thomas Scheffler (yagee)
055     * @version $Revision: 15202 $ $Date: 2009-05-15 17:00:44 +0200 (Fri, 15 May 2009) $
056     */
057    public class MCRCheckClassACLServlet extends MCRServlet {
058    
059        private static final long serialVersionUID = 1L;
060    
061        // The logger
062        protected static Logger LOGGER = Logger.getLogger(MCRCheckClassACLServlet.class);
063    
064        // the configured permissions
065        private static String storedrules = MCRConfiguration.instance().getString("MCR.Access.StorePermissions", "read,write,delete");
066    
067        // The User Manager
068        protected static MCRUserMgr UM = MCRUserMgr.instance();
069    
070        /**
071         * This method overrides doGetPost of MCRServlet and handels all actions
072         * against the ACL data.
073         * 
074         * @param job
075         *            the MCRServlet job instance
076         */
077        public void doGetPost(MCRServletJob job) throws Exception {
078            // read the XML data
079            MCREditorSubmission sub = (MCREditorSubmission) (job.getRequest().getAttribute("MCREditorSubmission"));
080            org.jdom.Document indoc = sub.getXML();
081    
082            // read the parameter
083            MCRRequestParameters parms;
084    
085            if (sub == null) {
086                parms = new MCRRequestParameters(job.getRequest());
087            } else {
088                parms = sub.getParameters();
089            }
090    
091            String oldmcrid = parms.getParameter("mcrid");
092            LOGGER.debug("XSL.target.param.0 = " + oldmcrid);
093            MCRObjectID ID = new MCRObjectID(oldmcrid);
094    
095            // get the MCRSession object for the current thread from the session
096            // manager.
097            MCRSession mcrSession = MCRSessionMgr.getCurrentSession();
098            String lang = mcrSession.getCurrentLanguage();
099            LOGGER.info("LANG = " + lang);
100    
101            // create a service object and prepare it
102            Element outelm = prepareService((org.jdom.Document) indoc.clone(), ID, job, lang);
103    
104            // Save the prepared metadata object
105            boolean okay = storeService(outelm, job, ID);
106    
107            // call the getNextURL and sendMail methods
108            String url = getNextURL(ID, okay);
109            sendMail(ID);
110    
111            job.getResponse().sendRedirect(job.getResponse().encodeRedirectURL(getBaseURL() + url));
112        }
113    
114        /**
115         * The method return an URL with the next working step. If okay flag is
116         * true, the object will present else it shows the error page.
117         * 
118         * @param ID
119         *            the MCRObjectID of the MCRObject
120         * @param okay
121         *            the return value of the store operation
122         * @return the next URL as String
123         */
124        protected String getNextURL(MCRObjectID ID, boolean okay) throws MCRActiveLinkException {
125            StringBuffer sb = new StringBuffer();
126            if (okay) {
127                sb.append("browse?mode=edit");
128            } else {
129                sb.append(MCRConfiguration.instance().getString("MCR.SWF.PageDir", "")).append(MCRConfiguration.instance().getString("MCR.SWF.PageErrorStore", "editor_error_store.xml"));
130            }
131            return sb.toString();
132        }
133    
134        /**
135         * The method send a message to the mail address for the MCRObjectType.
136         * 
137         * @param ID
138         *            the MCRObjectID of the MCRObject
139         */
140        public final void sendMail(MCRObjectID ID) {
141            LOGGER.warn("Send mail is not configured for modify ACLs");
142        }
143    
144        /**
145         * The method read the incoming servacls JDOM tree in a MCRService and
146         * prepare this by the following rules. After them it return a JDOM Element
147         * of servacls as clone of the prepared data.
148         * 
149         * @param jdom_in
150         *            the JDOM tree from the editor
151         * @param ID
152         *            the MCRObjectID of the MCRObject
153         * @param job
154         *            the MCRServletJob data
155         * @param lang
156         *            the current language
157         */
158        @SuppressWarnings("unchecked")
159        protected Element prepareService(org.jdom.Document jdom_in, MCRObjectID ID, MCRServletJob job, String lang) throws Exception {
160            Element elm_out = null;
161            ArrayList <String>logtext = new ArrayList<String>();
162            Element root = jdom_in.getRootElement();
163            if (root != null) {
164                Element servacls = root.getChild("servacls");
165                if (servacls != null) {
166                    List<Element> servacllist = servacls.getChildren("servacl");
167                    if (servacllist.size() != 0) {
168                        for (int i = 0; i < servacllist.size(); i++) {
169                            Element servacl = servacllist.get(i);
170                            Element outcond = servacl.getChild("condition");
171                            if (outcond != null) {
172                                Element outbool = outcond.getChild("boolean");
173                                if (outbool != null) {
174                                    List<Element> inbool = outbool.getChildren("boolean");
175                                    String outoper = outbool.getAttributeValue("operator");
176                                    if (inbool.size() != 0 && outoper != null && !outoper.equals("true")) {
177                                        for (int j = 0; j < inbool.size(); j++) {
178                                            List<Element> incondlist = inbool.get(j).getChildren("condition");
179                                            int k = incondlist.size();
180                                            if (k != 0) {
181                                                for (int l = 0; l < k; l++) {
182                                                    Element incond = incondlist.get(l);
183                                                    String condvalue = incond.getAttributeValue("value");
184                                                    if (condvalue == null || (condvalue = condvalue.trim()).length() == 0) {
185                                                        ((Element) inbool.get(j)).removeContent(incond);
186                                                        k--;
187                                                        l--;
188                                                        continue;
189                                                    }
190                                                    String condfield = incond.getAttributeValue("field");
191                                                    if (condfield.equals("user")) {
192                                                        if (!UM.existUser(condvalue)) {
193                                                            ((Element) inbool.get(j)).removeContent(incond);
194                                                            k--;
195                                                            l--;
196                                                            continue;
197                                                        }
198                                                    }
199                                                    if (condfield.equals("group")) {
200                                                        if (!UM.existGroup(condvalue)) {
201                                                            ((Element) inbool.get(j)).removeContent(incond);
202                                                            k--;
203                                                            l--;
204                                                            continue;
205                                                        }
206                                                    }
207                                                }
208                                                if (k == 1) {
209                                                    Element newtrue = new Element("boolean");
210                                                    newtrue.setAttribute("operator", "true");
211                                                    ((Element) inbool.get(j)).addContent(newtrue);
212                                                }
213                                            } else {
214                                                logtext.add("Can't find an inner condition element.");
215                                            }
216                                        }
217                                    } else {
218                                        if (outoper == null || !outoper.equals("true")) {
219                                            logtext.add("Wrong structure of MyCoRe ACL JDOM in boolean.");
220                                        }
221                                    }
222                                } else {
223                                    outbool = new Element("boolean");
224                                    outbool.setAttribute("operator", "true");
225                                    outcond.addContent(outbool);
226                                }
227                            } else {
228                                logtext.add("Can't find a condition element.");
229                            }
230                        }
231                    } else {
232                        logtext.add("Can't find a servacl element.");
233                    }
234                } else {
235                    logtext.add("Can't find the servacls element.");
236                }
237            } else {
238                logtext.add("The service part is null.");
239            }
240            elm_out = (Element) root.clone();
241            errorHandlerValid(job, logtext, ID, lang);
242            return elm_out;
243        }
244    
245        /**
246         * The method store the incoming service data from the ACL editor to the
247         * workflow.
248         * 
249         * @param outelm
250         *            the service subelement of an MCRObject
251         * @param job
252         *            the MCRServletJob instance
253         * @param ID
254         *            the MCRObjectID
255         */
256        public final boolean storeService(Element outelm, MCRServletJob job, MCRObjectID ID) {
257            // check current state
258            Collection<String> li = MCRAccessManager.getPermissionsForID(ID.getId());
259            int aclsize = 0;
260            if (li != null) {
261                aclsize = li.size();
262            }
263            if (aclsize == 0) {
264                LOGGER.warn("They are no ACLs defined for classification " + ID.getId());
265                return false;
266            }
267            // check incoming ACLs
268            int rulesize = 0;
269            MCRObjectService serv = new MCRObjectService();
270            try {
271                serv.setFromDOM(outelm);
272                rulesize = serv.getRulesSize();
273            } catch (Exception e) {
274                e.printStackTrace();
275            }
276            if (rulesize == 0) {
277                LOGGER.warn("The new ACL conditions for classification" + ID.getId() + " are empty!");
278            }
279            while (0 < rulesize) {
280                Element conditions = serv.getRule(0).getCondition();
281                String permission = serv.getRule(0).getPermission();
282                if (storedrules.indexOf(permission) != -1) {
283                    if (li.contains(permission)) {
284                        MCRAccessManager.updateRule(ID.getId(), permission, conditions, "");
285                    } else {
286                        MCRAccessManager.addRule(ID.getId(), permission, conditions, "");
287                    }
288                }
289                serv.removeRule(0);
290                rulesize--;
291            }
292    
293            LOGGER.info("ACL of classification " + ID.getId() + " stored in the server.");
294            return true;
295        }
296    
297        /**
298         * An internal method to handle validation errors.
299         * 
300         * @param job
301         *            the MCRServletJob instance
302         * @param logtext
303         *            a list of log texts as strings
304         * @param ID
305         *            the current MCRObjectID
306         * @param lang
307         *            the current language
308         */
309        @SuppressWarnings("unchecked")
310        private final void errorHandlerValid(MCRServletJob job, List<String> logtext, MCRObjectID ID, String lang) throws Exception {
311            if (logtext.size() == 0) {
312                return;
313            }
314    
315            // write to the log file
316            for (int i = 0; i < logtext.size(); i++) {
317                LOGGER.error(logtext.get(i));
318            }
319    
320            // prepare editor with error messages
321            String pagedir = MCRConfiguration.instance().getString("MCR.editor_page_dir", "");
322            String myfile = pagedir + MCRConfiguration.instance().getString("MCR.editor_page_error_formular", "editor_error_formular.xml");
323            org.jdom.Document jdom = null;
324    
325            try {
326                InputStream in = (new URL(getBaseURL() + myfile + "?XSL.Style=xml")).openStream();
327    
328                if (in == null) {
329                    throw new MCRConfigurationException("Can't read editor file " + myfile);
330                }
331    
332                jdom = new org.jdom.input.SAXBuilder().build(in);
333    
334                Element root = jdom.getRootElement();
335                List<Element> sectionlist = root.getChildren("section");
336    
337                for (int i = 0; i < sectionlist.size(); i++) {
338                    Element section = (Element) sectionlist.get(i);
339    
340                    if (!section.getAttributeValue("lang", org.jdom.Namespace.XML_NAMESPACE).equals(lang.toLowerCase())) {
341                        continue;
342                    }
343    
344                    Element p = new Element("p");
345                    section.addContent(0, p);
346    
347                    Element center = new Element("center");
348    
349                    // the error message
350                    Element table = new Element("table");
351                    table.setAttribute("width", "80%");
352    
353                    for (int j = 0; j < logtext.size(); j++) {
354                        Element tr = new Element("tr");
355                        Element td = new Element("td");
356                        Element el = new Element("font");
357                        el.setAttribute("color", "red");
358                        el.addContent((String) logtext.get(j));
359                        td.addContent(el);
360                        tr.addContent(td);
361                        table.addContent(tr);
362                    }
363    
364                    center.addContent(table);
365                    section.addContent(1, center);
366                    p = new Element("p");
367                    section.addContent(2, p);
368    
369                    // the edit button
370                    Element form = section.getChild("form");
371                    form.setAttribute("action", job.getResponse().encodeRedirectURL(getBaseURL() + "servlets/MCRStartEditorServlet"));
372    
373                    Element input1 = new Element("input");
374                    input1.setAttribute("name", "lang");
375                    input1.setAttribute("type", "hidden");
376                    input1.setAttribute("value", lang);
377                    form.addContent(input1);
378    
379                    Element input2 = new Element("input");
380                    input2.setAttribute("name", "se_mcrid");
381                    input2.setAttribute("type", "hidden");
382                    input2.setAttribute("value", ID.getId());
383                    form.addContent(input2);
384    
385                    Element input3 = new Element("input");
386                    input3.setAttribute("name", "type");
387                    input3.setAttribute("type", "hidden");
388                    input3.setAttribute("value", ID.getTypeId());
389                    form.addContent(input3);
390                }
391            } catch (org.jdom.JDOMException e) {
392                throw new MCRException("Can't read editor file " + myfile + " or it has a parse error.", e);
393            }
394    
395            // restart editor
396            job.getRequest().setAttribute("XSL.Style", lang);
397            getLayoutService().doLayout(job.getRequest(), job.getResponse(), jdom);
398        }
399    }