aboutsummaryrefslogtreecommitdiffstats
path: root/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java
blob: 1a9b9b60cd46ffdd68ba4fecff02767bb4250b8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.node.admin.task.util.fs;

import com.yahoo.vespa.hosted.node.admin.nodeagent.UserScope;
import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser;

import java.io.IOException;
import java.nio.file.attribute.GroupPrincipal;
import java.nio.file.attribute.UserPrincipal;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.attribute.UserPrincipalNotFoundException;
import java.util.Objects;
import java.util.function.Function;

/**
 * @author freva
 */
public class ContainerUserPrincipalLookupService extends UserPrincipalLookupService {

    private final UserPrincipalLookupService baseFsUserPrincipalLookupService;
    private final UserScope userScope;

    ContainerUserPrincipalLookupService(UserPrincipalLookupService baseFsUserPrincipalLookupService, UserScope userScope) {
        this.baseFsUserPrincipalLookupService = Objects.requireNonNull(baseFsUserPrincipalLookupService);
        this.userScope = Objects.requireNonNull(userScope);
    }

    public UserScope userScope() { return userScope; }

    public int userIdOnHost(int containerUid)  { return userScope.namespace().userIdOnHost(containerUid); }
    public int groupIdOnHost(int containerGid) { return userScope.namespace().groupIdOnHost(containerGid); }
    public int userIdInContainer(int hostUid)  { return userScope.namespace().userIdInContainer(hostUid); }
    public int groupIdInContainer(int hostGid) { return userScope.namespace().groupIdInContainer(hostGid); }

    @Override
    public ContainerUserPrincipal lookupPrincipalByName(String name) throws IOException {
        int containerUid = resolveName(name, UnixUser::uid, UnixUser::name);
        String user = resolveId(containerUid, UnixUser::uid, UnixUser::name);
        String hostUid = String.valueOf(userIdOnHost(containerUid));
        return new ContainerUserPrincipal(containerUid, user, baseFsUserPrincipalLookupService.lookupPrincipalByName(hostUid));
    }

    @Override
    public ContainerGroupPrincipal lookupPrincipalByGroupName(String group) throws IOException {
        int containerGid = resolveName(group, UnixUser::gid, UnixUser::group);
        String name = resolveId(containerGid, UnixUser::gid, UnixUser::group);
        String hostGid = String.valueOf(groupIdOnHost(containerGid));
        return new ContainerGroupPrincipal(containerGid, name, baseFsUserPrincipalLookupService.lookupPrincipalByGroupName(hostGid));
    }

    public ContainerUserPrincipal userPrincipal(int uid, UserPrincipal baseFsPrincipal) {
        String name = resolveId(uid, UnixUser::uid, UnixUser::name);
        return new ContainerUserPrincipal(uid, name, baseFsPrincipal);
    }
    
    public ContainerGroupPrincipal groupPrincipal(int gid, GroupPrincipal baseFsPrincipal) {
        String name = resolveId(gid, UnixUser::gid, UnixUser::group);
        return new ContainerGroupPrincipal(gid, name, baseFsPrincipal);
    }

    private String resolveId(int id, Function<UnixUser, Integer> idExtractor, Function<UnixUser, String> nameExtractor) {
        if (idExtractor.apply(userScope.root()) == id) return nameExtractor.apply(userScope.root());
        if (idExtractor.apply(userScope.vespa()) == id) return nameExtractor.apply(userScope.vespa());
        return String.valueOf(id);
    }

    private int resolveName(String name, Function<UnixUser, Integer> idExtractor, Function<UnixUser, String> nameExtractor) throws UserPrincipalNotFoundException {
        if (name.equals(nameExtractor.apply(userScope.root()))) return idExtractor.apply(userScope.root());
        if (name.equals(nameExtractor.apply(userScope.vespa()))) return idExtractor.apply(userScope.vespa());

        try {
            return Integer.parseInt(name);
        } catch (NumberFormatException ignored) {
            throw new UserPrincipalNotFoundException(name);
        }
    }

    private abstract static class NamedPrincipal implements UserPrincipal {
        private final int id;
        private final String name;
        private final UserPrincipal baseFsPrincipal;

        private NamedPrincipal(int id, String name, UserPrincipal baseFsPrincipal) {
            this.id = id;
            this.name = Objects.requireNonNull(name);
            this.baseFsPrincipal = Objects.requireNonNull(baseFsPrincipal);
        }

        @Override
        public final String getName() {
            return name;
        }

        public int id() {
            return id;
        }

        public UserPrincipal baseFsPrincipal() {
            return baseFsPrincipal;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            NamedPrincipal that = (NamedPrincipal) o;
            return id == that.id && baseFsPrincipal.equals(that.baseFsPrincipal);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, baseFsPrincipal);
        }

        @Override
        public String toString() {
            return "{id=" + id + ", baseFsPrincipal=" + baseFsPrincipal + '}';
        }
    }

    static final class ContainerUserPrincipal extends NamedPrincipal {
        private ContainerUserPrincipal(int id, String name, UserPrincipal baseFsPrincipal) { super(id, name, baseFsPrincipal); }
    }

    static final class ContainerGroupPrincipal extends NamedPrincipal implements GroupPrincipal {
        private ContainerGroupPrincipal(int id, String name, GroupPrincipal baseFsPrincipal) { super(id, name, baseFsPrincipal); }

        @Override public GroupPrincipal baseFsPrincipal() { return (GroupPrincipal) super.baseFsPrincipal(); }
    }
}