/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.web.service; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.SubmitLink; import org.apache.wicket.markup.html.form.validation.AbstractFormValidator; import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.platform.Service; import org.geoserver.security.impl.DataAccessRule; import org.geoserver.security.impl.ServiceAccessRule; import org.geoserver.security.web.AbstractSecurityPage; import org.geoserver.security.web.role.RuleRolesFormComponent; import org.geoserver.web.wicket.ParamResourceModel; /** * Abstract page binding a {@link DataAccessRule} */ @SuppressWarnings("serial") public abstract class AbstractServiceAccessRulePage extends AbstractSecurityPage { protected DropDownChoice<String> serviceChoice, methodChoice; protected RuleRolesFormComponent rolesFormComponent; public AbstractServiceAccessRulePage(final ServiceAccessRule rule) { // build the form Form form = new Form<Serializable>("form", new CompoundPropertyModel(rule)); add(form); form.add(new EmptyRolesValidator()); form.add(serviceChoice = new DropDownChoice<String>("service", getServiceNames())); serviceChoice.add(new OnChangeAjaxBehavior() { @Override protected void onUpdate(AjaxRequestTarget target) { methodChoice.updateModel(); target.add(methodChoice); } }); serviceChoice.setRequired(true); form.add(methodChoice = new DropDownChoice<String>("method", new MethodsModel(rule))); //we add on change behavior to ensure the underlying model is updated but don't actually // do anything on change... this allows us to keep state when someone adds a new role, // leaving the page, TODO: find a better way to do this //methodChoice.add(new OnChangeAjaxBehavior() { // @Override // protected void onUpdate(AjaxRequestTarget target) {} //}); methodChoice.setOutputMarkupId(true); methodChoice.setRequired(true); form.add(rolesFormComponent = new RuleRolesFormComponent("roles", new PropertyModel<Collection<String>>(rule, "roles"))); //new Model((Serializable)new ArrayList(rule.getRoles())))); // build the submit/cancel form.add(new SubmitLink("save") { @Override public void onSubmit() { onFormSubmit((ServiceAccessRule) getForm().getModelObject()); } }); form.add(new BookmarkablePageLink("cancel", ServiceAccessRulePage.class)); } /** * Implements the actual save action */ protected abstract void onFormSubmit(ServiceAccessRule rule); /** * Returns a sorted list of workspace names */ ArrayList<String> getServiceNames() { ArrayList<String> result = new ArrayList<String>(); for (Service ows : GeoServerExtensions.extensions(Service.class)) { if (!result.contains(ows.getId())) result.add(ows.getId()); } Collections.sort(result); result.add(0, "*"); return result; } class EmptyRolesValidator extends AbstractFormValidator { @Override public FormComponent<?>[] getDependentFormComponents() { return new FormComponent[] { rolesFormComponent }; } @Override public void validate(Form<?> form) { // only validate on final submit if (form.findSubmittingButton() != form.get("save")) { return; } updateModels(); String roleInputString = rolesFormComponent.getPalette().getRecorderComponent().getInput(); if ((roleInputString == null || roleInputString.trim().isEmpty()) && !rolesFormComponent.isHasAnyRole()) { form.error(new ParamResourceModel("emptyRoles", getPage()).getString()); } } } class MethodsModel implements IModel<List<String>> { ServiceAccessRule rule; MethodsModel(ServiceAccessRule rule) { this.rule = rule; } @Override public List<String> getObject() { ArrayList<String> result = new ArrayList<String>(); boolean flag = true; for (Service ows : GeoServerExtensions.extensions(Service.class)) { String service = rule.getService(); if (ows.getId().equals(service) && !result.contains(ows.getOperations()) && flag) { flag = false; result.addAll(ows.getOperations()); } } Collections.sort(result); result.add(0, "*"); return result; } @Override public void setObject(List<String> object) { throw new UnsupportedOperationException(); } @Override public void detach() { } } protected void updateModels() { serviceChoice.updateModel(); methodChoice.updateModel(); rolesFormComponent.updateModel(); } }