package io.cattle.platform.schema.processor; import io.cattle.platform.json.JsonMapper; import io.github.ibuildthecloud.gdapi.factory.SchemaFactory; import io.github.ibuildthecloud.gdapi.factory.impl.SchemaPostProcessor; import io.github.ibuildthecloud.gdapi.model.Action; import io.github.ibuildthecloud.gdapi.model.Field; import io.github.ibuildthecloud.gdapi.model.Schema; import io.github.ibuildthecloud.gdapi.model.impl.FieldImpl; import io.github.ibuildthecloud.gdapi.model.impl.SchemaImpl; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import javax.annotation.PostConstruct; import javax.inject.Inject; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AuthOverlayPostProcessor implements SchemaPostProcessor { private static final Logger log = LoggerFactory.getLogger(AuthOverlayPostProcessor.class); Map<String, Perm> perms = new LinkedHashMap<String, Perm>(); List<Pair<Pattern, Perm>> wildcards = new ArrayList<Pair<Pattern, Perm>>(); List<URL> resources; JsonMapper jsonMapper; @Override public SchemaImpl postProcessRegister(SchemaImpl schema, SchemaFactory factory) { Perm perm = getPerm(schema.getId()); return perm == null || perm.isRead() ? schema : null; } @Override public SchemaImpl postProcess(SchemaImpl schema, SchemaFactory factory) { Perm perm = getPerm(schema.getId()); if (perm != null) { schema.setCreate(perm.isCreate()); schema.setUpdate(perm.isUpdate()); schema.setDeletable(perm.isDelete()); } Iterator<Map.Entry<String, Field>> fieldIter = schema.getResourceFields().entrySet().iterator(); while (fieldIter.hasNext()) { Map.Entry<String, Field> entry = fieldIter.next(); Field field = entry.getValue(); perm = getPerm(factory, schema, entry.getKey()); if (perm == null) { continue; } if (!perm.isRead()) { fieldIter.remove(); } if (!(field instanceof FieldImpl)) { continue; } FieldImpl fieldImpl = (FieldImpl) field; fieldImpl.setCreate(perm.isCreate()); fieldImpl.setUpdate(perm.isUpdate()); fieldImpl.setReadOnCreateOnly(perm.isReadOnCreateOnly()); } Iterator<Map.Entry<String, Action>> actionIter = schema.getResourceActions().entrySet().iterator(); while (actionIter.hasNext()) { Map.Entry<String, Action> entry = actionIter.next(); perm = getPerm(factory, schema, "resourceActions." + entry.getKey()); if (perm == null) { continue; } if (!perm.isCreate()) { actionIter.remove(); } } return schema; } protected Perm getPerm(SchemaFactory factory, Schema schema, String field) { Schema start = schema; while (schema != null) { String name = String.format("%s.%s", schema.getId(), field); Perm perm = getPerm(name, false); if (perm != null) return perm; schema = factory.getSchema(schema.getParent()); } schema = start; while (schema != null) { String name = String.format("%s.%s", schema.getId(), field); Perm perm = getPerm(name, true); if (perm != null) return perm; schema = factory.getSchema(schema.getParent()); } return null; } protected Perm getPerm(String name) { return getPerm(name, true); } protected Perm getPerm(String name, boolean wildcard) { List<Perm> result = new ArrayList<Perm>(); if (wildcard) { for (Pair<Pattern, Perm> entry : wildcards) { if (entry.getLeft().matcher(name).matches()) { result.add(entry.getValue()); } } } Perm perm = perms.get(name); if (perm != null) { result.add(perm); } return result.size() == 0 ? null : result.get(result.size() - 1); } @PostConstruct public void init() throws IOException { for (URL url : resources) { log.info("Loading [{}] for schema auth", url); InputStream is = url.openStream(); try { Map<String, Object> values = jsonMapper.readValue(is); Object value = values.get("authorize"); if (value instanceof Map) { load((Map<?, ?>) value); } } finally { IOUtils.closeQuietly(is); } } } protected void load(Map<?, ?> values) { for (Map.Entry<?, ?> entry : values.entrySet()) { String key = entry.getKey().toString(); Perm perm = new Perm(entry.getValue().toString()); if (key.contains("*")) { wildcards.add(new ImmutablePair<Pattern, Perm>(Pattern.compile(key), perm)); } else { perms.put(key, perm); } } } public List<URL> getResources() { return resources; } @Inject public void setResources(List<URL> resources) { this.resources = resources; } public JsonMapper getJsonMapper() { return jsonMapper; } @Inject public void setJsonMapper(JsonMapper jsonMapper) { this.jsonMapper = jsonMapper; } private static class Perm { boolean read, create, update, delete, readOnCreateOnly; public Perm(String value) { super(); create = value.contains("c"); read = value.contains("r"); update = value.contains("u"); delete = value.contains("d"); readOnCreateOnly = value.contains("o"); } public boolean isRead() { return read; } public boolean isCreate() { return create; } public boolean isUpdate() { return update; } public boolean isDelete() { return delete; } public boolean isReadOnCreateOnly() { return readOnCreateOnly; } } }