org.dcache.gplazma.roles.RolesPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.dcache.gplazma.roles.RolesPlugin.java

Source

/*
 * dCache - http://www.dcache.org/
 *
 * Copyright (C) 2017 Deutsches Elektronen-Synchrotron
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.dcache.gplazma.roles;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;

import java.security.Principal;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

import org.dcache.auth.DesiredRole;
import org.dcache.auth.GidPrincipal;
import org.dcache.auth.attributes.LoginAttribute;
import org.dcache.auth.attributes.LoginAttributes;
import org.dcache.auth.attributes.Role;
import org.dcache.auth.attributes.UnassertedRole;
import org.dcache.gplazma.AuthenticationException;
import org.dcache.gplazma.plugins.GPlazmaSessionPlugin;

/**
 * A plugin for processing a user's DesiredRole principals and, if authorised,
 * adding the corresponding Role.
 */
public class RolesPlugin implements GPlazmaSessionPlugin {
    @VisibleForTesting
    static final String ADMIN_GID_PROPERTY_NAME = "gplazma.roles.admin-gid";

    @VisibleForTesting
    static final String OBSERVER_GID_PROPERTY_NAME = "gplazma.roles.observer-gid";

    private final Long adminGid;
    private final Long observerGid;

    public RolesPlugin(Properties properties) {
        this.adminGid = getGidForRole(properties, ADMIN_GID_PROPERTY_NAME);
        this.observerGid = getGidForRole(properties, OBSERVER_GID_PROPERTY_NAME);
    }

    @Override
    public void session(Set<Principal> principals, Set<Object> attributes) throws AuthenticationException {
        Set<Role> allowedRoles = allAuthorizedRoles(principals);
        Set<Role> desiredRoles = principals.stream().filter(DesiredRole.class::isInstance)
                .map(DesiredRole.class::cast).map(DesiredRole::getName).map(Role::new).collect(Collectors.toSet());

        Set<Role> unauthorizedRoles = Sets.difference(desiredRoles, allowedRoles).copyInto(new HashSet<>());

        if (!unauthorizedRoles.isEmpty()) {
            String description = unauthorizedRoles.size() == 1 ? unauthorizedRoles.iterator().next().toString()
                    : unauthorizedRoles.stream().map(LoginAttribute::toString)
                            .collect(Collectors.joining(",", "[", "]"));
            throw new AuthenticationException("unauthorized for " + description);
        }

        attributes.addAll(desiredRoles);
        Sets.difference(allowedRoles, desiredRoles).stream().map(Role::getRole).map(UnassertedRole::new)
                .forEach(attributes::add);
    }

    private Set<Role> allAuthorizedRoles(Set<Principal> principals) {
        Set<Role> roles = new HashSet<>();

        /*
         *  It is possible for the admin and observer gids to be the same,
         *  so unfortunately we need to check them separately.
         */
        principals.stream().filter(GidPrincipal.class::isInstance).map(GidPrincipal.class::cast)
                .map(GidPrincipal::getGid).forEach((gid) -> {
                    if (adminGid != null && gid == adminGid.longValue()) {
                        roles.add(LoginAttributes.adminRole());
                    }

                    if (observerGid != null && gid == observerGid.longValue()) {
                        roles.add(LoginAttributes.observerRole());
                    }
                });

        return roles;
    }

    private static Long getGidForRole(Properties properties, String name) {
        String property = Strings.emptyToNull(properties.getProperty(name));

        if (property == null) {
            return null;
        }

        try {
            return Long.parseLong(property, 10);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Badly formatted " + name + " value: " + e);
        }
    }
}