summaryrefslogtreecommitdiffstats
path: root/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java
blob: ae65f6a7f7f0e2b57e9918dd0695b9fd84f92516 (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
// Copyright Yahoo. 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.UserNamespace;

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;

/**
 * @author valerijf
 */
class ContainerUserPrincipalLookupService extends UserPrincipalLookupService {

    private final UserPrincipalLookupService baseFsUserPrincipalLookupService;
    private final UserNamespace userNamespace;

    ContainerUserPrincipalLookupService(UserPrincipalLookupService baseFsUserPrincipalLookupService, UserNamespace userNamespace) {
        this.baseFsUserPrincipalLookupService = Objects.requireNonNull(baseFsUserPrincipalLookupService);
        this.userNamespace = Objects.requireNonNull(userNamespace);
    }

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

    @Override
    public ContainerUserPrincipal lookupPrincipalByName(String name) throws IOException {
        int containerUid = resolveName(name, userNamespace.vespaUser(), userNamespace.vespaUserId());
        String user = resolveId(containerUid, userNamespace.vespaUser(), userNamespace.vespaUserId());
        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, userNamespace.vespaGroup(), userNamespace.vespaGroupId());
        String name = resolveId(containerGid, userNamespace.vespaGroup(), userNamespace.vespaGroupId());
        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, userNamespace.vespaUser(), userNamespace.vespaUserId());
        return new ContainerUserPrincipal(uid, name, baseFsPrincipal);
    }
    
    public ContainerGroupPrincipal groupPrincipal(int gid, GroupPrincipal baseFsPrincipal) {
        String name = resolveId(gid, userNamespace.vespaGroup(), userNamespace.vespaGroupId());
        return new ContainerGroupPrincipal(gid, name, baseFsPrincipal);
    }

    private String resolveId(int id, String vespaName, int vespaId) {
        if (id == 0) return "root";
        if (id == vespaId) return vespaName;
        return String.valueOf(id);
    }

    private int resolveName(String name, String vespaName, int vespaId) throws UserPrincipalNotFoundException {
        if (name.equals("root")) return 0;
        if (name.equals(vespaName)) return vespaId;

        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(); }
    }
}