All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.security.IPAddressAuthModule Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.security;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.yamcs.InitException;
import org.yamcs.Spec;
import org.yamcs.Spec.OptionType;
import org.yamcs.YConfiguration;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.ipfilter.IpFilterRule;
import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ipfilter.IpSubnetFilterRule;

/**
 * An AuthModule that enforces a login of one fixed user account, where the remote IP address must match one of the
 * configured IP address rules.
 */
public class IPAddressAuthModule extends AbstractHttpRequestAuthModule {

    protected static final String OPTION_ADDRESS = "address";
    protected static final String OPTION_USERNAME = "username";
    protected static final String OPTION_NAME = "name";
    protected static final String OPTION_EMAIL = "email";
    protected static final String OPTION_SUPERUSER = "superuser";
    protected static final String OPTION_PRIVILEGES = "privileges";

    private List rules = new ArrayList<>();

    private AuthenticationInfo authenticationInfo;
    private AuthorizationInfo authorizationInfo;

    @Override
    public Spec getSpec() {
        var spec = new Spec();
        spec.addOption(OPTION_ADDRESS, OptionType.LIST_OR_ELEMENT)
                .withElementType(OptionType.STRING)
                .withRequired(true);
        spec.addOption(OPTION_USERNAME, OptionType.STRING).withRequired(true);
        spec.addOption(OPTION_NAME, OptionType.STRING);
        spec.addOption(OPTION_EMAIL, OptionType.STRING);
        spec.addOption(OPTION_SUPERUSER, OptionType.BOOLEAN).withDefault(false);
        spec.addOption(OPTION_PRIVILEGES, OptionType.ANY);
        return spec;
    }

    @Override
    public void init(YConfiguration args) throws InitException {
        var username = args.getString(OPTION_USERNAME);
        authenticationInfo = new AuthenticationInfo(this, username);

        var name = args.getString(OPTION_NAME, null);
        authenticationInfo.setDisplayName(name);

        var email = args.getString(OPTION_EMAIL, null);
        authenticationInfo.setEmail(email);

        authorizationInfo = new AuthorizationInfo();
        if (args.getBoolean(OPTION_SUPERUSER)) {
            authorizationInfo.grantSuperuser();
        }
        if (args.containsKey(OPTION_PRIVILEGES)) {
            var privilegeConfigs = args.getConfig(OPTION_PRIVILEGES);
            for (var privilegeName : privilegeConfigs.getKeys()) {
                var objects = privilegeConfigs. getList(privilegeName);
                if (privilegeName.equals("System")) {
                    for (var object : objects) {
                        authorizationInfo.addSystemPrivilege(new SystemPrivilege(object));
                    }
                } else {
                    var type = new ObjectPrivilegeType(privilegeName);
                    for (var object : objects) {
                        authorizationInfo.addObjectPrivilege(new ObjectPrivilege(type, object));
                    }
                }
            }
        }

        try {
            for (var address : args. getList(OPTION_ADDRESS)) {
                if (address.indexOf('/') > 0) {
                    var parts = address.split("\\/");
                    var ipAddress = InetAddress.getByName(parts[0]);
                    var cidrPrefix = Integer.parseInt(parts[1]);
                    rules.add(new IpSubnetFilterRule(ipAddress, cidrPrefix, IpFilterRuleType.ACCEPT));
                } else {
                    var ipAddress = InetAddress.getByName(address);
                    if (ipAddress instanceof Inet4Address) {
                        rules.add(new IpSubnetFilterRule(ipAddress, 32, IpFilterRuleType.ACCEPT));
                    } else if (ipAddress instanceof Inet6Address) {
                        rules.add(new IpSubnetFilterRule(ipAddress, 128, IpFilterRuleType.ACCEPT));
                    } else {
                        throw new IllegalArgumentException("Only IPv4 and IPv6 addresses are supported");
                    }
                }
            }
        } catch (UnknownHostException e) {
            throw new InitException(e);
        }
    }

    @Override
    public boolean handles(ChannelHandlerContext ctx, HttpRequest request) {
        var remoteAddress = ctx.channel().remoteAddress();
        return accept((InetSocketAddress) remoteAddress);
    }

    @Override
    public AuthenticationInfo getAuthenticationInfo(
            ChannelHandlerContext ctx, HttpRequest request) throws AuthenticationException {
        var remoteAddress = ctx.channel().remoteAddress();
        if (accept((InetSocketAddress) remoteAddress)) {
            return authenticationInfo;
        } else {
            return null;
        }
    }

    @Override
    public AuthorizationInfo getAuthorizationInfo(AuthenticationInfo authenticationInfo) throws AuthorizationException {
        var incomingUsername = authenticationInfo.getUsername();
        if (incomingUsername.equals(this.authenticationInfo.getUsername())) {
            return authorizationInfo;
        } else {
            return new AuthorizationInfo();
        }
    }

    @Override
    public boolean verifyValidity(AuthenticationInfo authenticationInfo) {
        return authenticationInfo.equals(authenticationInfo);
    }

    private boolean accept(InetSocketAddress remoteAddress) {
        for (var rule : rules) {
            if (rule.matches(remoteAddress)) {
                return rule.ruleType() == IpFilterRuleType.ACCEPT;
            }
        }
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy