Skip to content

Commit

Permalink
Make RestPermissions implement PluginPermissions
Browse files Browse the repository at this point in the history
- Move plugin unrelated code to Permissions class
- Add readerBasePermissions() method to PluginPermissions interface
  • Loading branch information
bernd committed Mar 2, 2016
1 parent de678a5 commit 2fe82f5
Show file tree
Hide file tree
Showing 13 changed files with 334 additions and 164 deletions.
Expand Up @@ -34,6 +34,7 @@
import org.graylog2.shared.bindings.SharedPeriodicalBindings; import org.graylog2.shared.bindings.SharedPeriodicalBindings;
import org.graylog2.shared.bindings.ValidatorModule; import org.graylog2.shared.bindings.ValidatorModule;
import org.graylog2.shared.initializers.ServiceManagerListener; import org.graylog2.shared.initializers.ServiceManagerListener;
import org.graylog2.shared.security.SecurityBindings;
import org.graylog2.shared.system.activities.Activity; import org.graylog2.shared.system.activities.Activity;
import org.graylog2.shared.system.activities.ActivityWriter; import org.graylog2.shared.system.activities.ActivityWriter;
import org.graylog2.shared.system.stats.SystemStatsModule; import org.graylog2.shared.system.stats.SystemStatsModule;
Expand Down Expand Up @@ -163,6 +164,7 @@ protected List<Module> getSharedBindingsModules() {
final List<Module> result = super.getSharedBindingsModules(); final List<Module> result = super.getSharedBindingsModules();


result.add(new GenericBindings()); result.add(new GenericBindings());
result.add(new SecurityBindings());
result.add(new ServerStatusBindings(capabilities())); result.add(new ServerStatusBindings(capabilities()));
result.add(new ValidatorModule()); result.add(new ValidatorModule());
result.add(new SharedPeriodicalBindings()); result.add(new SharedPeriodicalBindings());
Expand Down
Expand Up @@ -24,7 +24,7 @@
import org.graylog2.plugin.database.ValidationException; import org.graylog2.plugin.database.ValidationException;
import org.graylog2.plugin.database.users.User; import org.graylog2.plugin.database.users.User;
import org.graylog2.plugin.periodical.Periodical; import org.graylog2.plugin.periodical.Periodical;
import org.graylog2.shared.security.RestPermissions; import org.graylog2.shared.security.Permissions;
import org.graylog2.shared.users.UserService; import org.graylog2.shared.users.UserService;
import org.graylog2.users.RoleService; import org.graylog2.users.RoleService;
import org.slf4j.Logger; import org.slf4j.Logger;
Expand All @@ -45,13 +45,13 @@ public class UserPermissionMigrationPeriodical extends Periodical {


private final UserService userService; private final UserService userService;
private final RoleService roleService; private final RoleService roleService;
private final RestPermissions permissions; private final Permissions permissions;
private final ClusterConfigService clusterConfigService; private final ClusterConfigService clusterConfigService;


@Inject @Inject
public UserPermissionMigrationPeriodical(final UserService userService, public UserPermissionMigrationPeriodical(final UserService userService,
final RoleService roleService, final RoleService roleService,
final RestPermissions permissions, final Permissions permissions,
final ClusterConfigService clusterConfigService) { final ClusterConfigService clusterConfigService) {
this.userService = userService; this.userService = userService;
this.roleService = roleService; this.roleService = roleService;
Expand Down
Expand Up @@ -24,16 +24,16 @@


@JsonAutoDetect @JsonAutoDetect
@AutoValue @AutoValue
public abstract class RestPermission { public abstract class Permission {
@JsonProperty("permission") @JsonProperty("permission")
public abstract String permission(); public abstract String permission();


@JsonProperty("description") @JsonProperty("description")
public abstract String description(); public abstract String description();


@JsonCreator @JsonCreator
public static RestPermission create(@JsonProperty("permission") @NotBlank String permission, public static Permission create(@JsonProperty("permission") @NotBlank String permission,
@JsonProperty("description") String description) { @JsonProperty("description") String description) {
return new AutoValue_RestPermission(permission, description); return new AutoValue_Permission(permission, description);
} }
} }
Expand Up @@ -19,5 +19,7 @@
import java.util.Set; import java.util.Set;


public interface PluginPermissions { public interface PluginPermissions {
Set<RestPermission> permissions(); Set<Permission> permissions();

Set<Permission> readerBasePermissions();
} }
Expand Up @@ -26,7 +26,7 @@
import org.apache.shiro.authz.annotation.RequiresGuest; import org.apache.shiro.authz.annotation.RequiresGuest;
import org.graylog2.rest.models.system.responses.ReaderPermissionResponse; import org.graylog2.rest.models.system.responses.ReaderPermissionResponse;
import org.graylog2.shared.rest.resources.RestResource; import org.graylog2.shared.rest.resources.RestResource;
import org.graylog2.shared.security.RestPermissions; import org.graylog2.shared.security.Permissions;


import javax.inject.Inject; import javax.inject.Inject;
import javax.ws.rs.GET; import javax.ws.rs.GET;
Expand All @@ -43,10 +43,10 @@
@Path("/system/permissions") @Path("/system/permissions")
@Produces(APPLICATION_JSON) @Produces(APPLICATION_JSON)
public class PermissionsResource extends RestResource { public class PermissionsResource extends RestResource {
private final RestPermissions permissions; private final Permissions permissions;


@Inject @Inject
public PermissionsResource(final RestPermissions permissions) { public PermissionsResource(final Permissions permissions) {
this.permissions = permissions; this.permissions = permissions;
} }


Expand All @@ -55,7 +55,7 @@ public PermissionsResource(final RestPermissions permissions) {
@RequiresGuest // turns off authentication for this action @RequiresGuest // turns off authentication for this action
@ApiOperation(value = "Get all available user permissions.") @ApiOperation(value = "Get all available user permissions.")
public Map<String, Map<String, Collection<String>>> permissions() { public Map<String, Map<String, Collection<String>>> permissions() {
return ImmutableMap.of("permissions", permissions.allPermissions()); return ImmutableMap.of("permissions", permissions.allPermissionsMap());
} }


@GET @GET
Expand Down
Expand Up @@ -31,18 +31,17 @@
import org.graylog2.plugin.inputs.MessageInput; import org.graylog2.plugin.inputs.MessageInput;
import org.graylog2.plugin.inputs.util.ThroughputCounter; import org.graylog2.plugin.inputs.util.ThroughputCounter;
import org.graylog2.plugin.system.NodeId; import org.graylog2.plugin.system.NodeId;
import org.graylog2.shared.bindings.providers.OkHttpClientProvider;
import org.graylog2.shared.bindings.providers.EventBusProvider; import org.graylog2.shared.bindings.providers.EventBusProvider;
import org.graylog2.shared.bindings.providers.MetricRegistryProvider; import org.graylog2.shared.bindings.providers.MetricRegistryProvider;
import org.graylog2.shared.bindings.providers.NodeIdProvider; import org.graylog2.shared.bindings.providers.NodeIdProvider;
import org.graylog2.shared.bindings.providers.OkHttpClientProvider;
import org.graylog2.shared.bindings.providers.ServiceManagerProvider; import org.graylog2.shared.bindings.providers.ServiceManagerProvider;
import org.graylog2.shared.bindings.providers.SystemOkHttpClientProvider; import org.graylog2.shared.bindings.providers.SystemOkHttpClientProvider;
import org.graylog2.shared.buffers.InputBufferImpl; import org.graylog2.shared.buffers.InputBufferImpl;
import org.graylog2.shared.buffers.ProcessBuffer; import org.graylog2.shared.buffers.ProcessBuffer;
import org.graylog2.shared.buffers.processors.DecodingProcessor; import org.graylog2.shared.buffers.processors.DecodingProcessor;
import org.graylog2.shared.inputs.InputRegistry; import org.graylog2.shared.inputs.InputRegistry;
import org.graylog2.shared.inputs.InputStateListener; import org.graylog2.shared.inputs.InputStateListener;
import org.graylog2.shared.security.RestPermissions;
import org.graylog2.shared.stats.ThroughputStats; import org.graylog2.shared.stats.ThroughputStats;
import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.HashedWheelTimer;


Expand Down Expand Up @@ -80,8 +79,6 @@ protected void configure() {


bind(OkHttpClient.class).toProvider(OkHttpClientProvider.class).asEagerSingleton(); bind(OkHttpClient.class).toProvider(OkHttpClientProvider.class).asEagerSingleton();
bind(OkHttpClient.class).annotatedWith(Names.named("systemHttpClient")).toProvider(SystemOkHttpClientProvider.class).asEagerSingleton(); bind(OkHttpClient.class).annotatedWith(Names.named("systemHttpClient")).toProvider(SystemOkHttpClientProvider.class).asEagerSingleton();

bind(RestPermissions.class).asEagerSingleton();
} }


private void bindEventBusListeners() { private void bindEventBusListeners() {
Expand Down
@@ -0,0 +1,122 @@
/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see <http://www.gnu.org/licenses/>.
*/
package org.graylog2.shared.security;

import com.google.common.base.Splitter;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
import org.graylog2.plugin.security.Permission;
import org.graylog2.plugin.security.PluginPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import static com.google.common.base.Strings.isNullOrEmpty;

public class Permissions {
private static final Logger LOG = LoggerFactory.getLogger(Permissions.class);

private final Set<String> allPermissions;
private final Set<String> readerBasePermissions;
private final Map<String, Collection<String>> allPermissionsMap;

@Inject
public Permissions(final Set<PluginPermissions> pluginPermissions) {
this.allPermissions = buildPermissions(pluginPermissions, PluginPermissions::permissions);
this.readerBasePermissions = buildPermissions(pluginPermissions, PluginPermissions::readerBasePermissions);
this.allPermissionsMap = buildPermissionsMap(allPermissions);
}

public Set<String> allPermissions() {
return allPermissions;
}

public Map<String, Collection<String>> allPermissionsMap() {
return allPermissionsMap;
}

public Set<String> readerBasePermissions() {
return readerBasePermissions;
}

public Set<String> readerPermissions(String username) {
final ImmutableSet.Builder<String> perms = ImmutableSet.<String>builder().addAll(readerBasePermissions);

if (isNullOrEmpty(username)) {
LOG.error("Username cannot be empty or null for creating reader permissions");
throw new IllegalArgumentException("Username was null or empty when getting reader permissions.");
}

perms.addAll(userSelfEditPermissions(username));

return perms.build();
}

public Set<String> userSelfEditPermissions(String username) {
ImmutableSet.Builder<String> perms = ImmutableSet.builder();
perms.add(perInstance(RestPermissions.USERS_EDIT, username));
perms.add(perInstance(RestPermissions.USERS_PASSWORDCHANGE, username));
return perms.build();
}

private String perInstance(String permission, String instance) {
// TODO check for existing instance etc (use DomainPermission subclass)
return permission + ":" + instance;
}

private interface PermissionListCallback {
Set<Permission> permissions(PluginPermissions permissions);
}

private static Set<String> buildPermissions(Set<PluginPermissions> pluginPermissions, PermissionListCallback callback) {
final Set<String> permissionSet = new HashSet<>();

for (PluginPermissions pluginPermission : pluginPermissions) {
for (Permission permission : callback.permissions(pluginPermission)) {
if (!permissionSet.contains(permission.permission())) {
permissionSet.add(permission.permission());
} else {
LOG.error("Error adding permissions for plugin: {}", pluginPermission.getClass().getCanonicalName());
throw new IllegalArgumentException("Duplicate permission found. Permission \"" + permission.toString() + "\" already exists!");
}
}
}

return permissionSet;
}

private Map<String, Collection<String>> buildPermissionsMap(Set<String> permissions) {
final ListMultimap<String, String> all = ArrayListMultimap.create();

for (String permission : permissions) {
final Iterator<String> split = Splitter.on(':').limit(2).split(permission).iterator();
final String group = split.next();
final String action = split.next();

all.put(group, action);
}

return all.asMap();
}
}

0 comments on commit 2fe82f5

Please sign in to comment.