aboutsummaryrefslogtreecommitdiffstats
path: root/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java
blob: 8e35bdccc2373a280ecebb7400187253630898cc (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
131
132
133
// 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 com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser;

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
 */
public class ContainerUserPrincipalLookupService extends UserPrincipalLookupService {

    private final UserPrincipalLookupService baseFsUserPrincipalLookupService;
    private final UserNamespace userNamespace;
    private final VespaUser vespaUser;

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

    public UserNamespace userNamespace() { return userNamespace; }
    public VespaUser vespaUser() { return vespaUser; }

    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, vespaUser.name(), vespaUser.uid());
        String user = resolveId(containerUid, vespaUser.name(), vespaUser.uid());
        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, vespaUser.group(), vespaUser.gid());
        String name = resolveId(containerGid, vespaUser.group(), vespaUser.gid());
        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, vespaUser.name(), vespaUser.uid());
        return new ContainerUserPrincipal(uid, name, baseFsPrincipal);
    }
    
    public ContainerGroupPrincipal groupPrincipal(int gid, GroupPrincipal baseFsPrincipal) {
        String name = resolveId(gid, vespaUser.group(), vespaUser.gid());
        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(); }
    }
}