File: strip.go

package info (click to toggle)
golang-github-canonical-candid 1.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 3,016 kB
  • sloc: python: 1,903; sh: 235; makefile: 81
file content (111 lines) | stat: -rw-r--r-- 3,188 bytes parent folder | download | duplicates (2)
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
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE.client file for details.

package candidclient

import (
	"context"
	"strings"

	"github.com/go-macaroon-bakery/macaroon-bakery/v3/bakery/checkers"
	"github.com/go-macaroon-bakery/macaroon-bakery/v3/bakery/identchecker"
	"gopkg.in/errgo.v1"
)

// StripDomain returns an implementation of identchecker.IdentityClient
// that strips the given
// domain name off any user and group names returned from it. It also
// adds it as an @ suffix when querying for ACL membership for names
// that don't already contain a domain.
//
// This is useful when an existing user of the identity manager needs to
// obtain backwardly compatible usernames when an identity manager is
// changed to add a domain suffix.
func StripDomain(candidClient *Client, domain string) identchecker.IdentityClient {
	return &domainStrippingClient{
		domain: "@" + domain,
		c:      candidClient,
	}
}

// domainStrippingClient implements IdentityClient by stripping a given
// domain off any declared users.
type domainStrippingClient struct {
	domain string
	c      *Client
}

// DeclaredIdentity implements IdentityClient.DeclaredIdentity.
func (c *domainStrippingClient) DeclaredIdentity(ctx context.Context, attrs map[string]string) (identchecker.Identity, error) {
	ident0, err := c.c.DeclaredIdentity(ctx, attrs)
	if err != nil {
		return nil, err
	}
	return &domainStrippingIdentity{
		Identity: ident0.(Identity),
		domain:   c.domain,
	}, nil
}

// DeclaredIdentity implements IdentityClient.IdentityCaveats.
func (c *domainStrippingClient) IdentityFromContext(ctx context.Context) (identchecker.Identity, []checkers.Caveat, error) {
	return c.c.IdentityFromContext(ctx)
}

var _ Identity = (*domainStrippingIdentity)(nil)

type domainStrippingIdentity struct {
	domain string
	Identity
}

// Username implements ACLUser.IdentityCaveats.
func (u *domainStrippingIdentity) Username() (string, error) {
	name, err := u.Identity.Username()
	if err != nil {
		return "", err
	}
	return strings.TrimSuffix(name, u.domain), nil
}

// Groups implements ACLUser.Groups.
func (u *domainStrippingIdentity) Groups() ([]string, error) {
	groups, err := u.Identity.Groups()
	if err != nil {
		return nil, err
	}
	for i, g := range groups {
		groups[i] = strings.TrimSuffix(g, u.domain)
	}
	return groups, nil
}

// Allow implements ACLUser.Allow by adding stripped
// domain to all names in acl that don't have a domain
// before calling the underlying Allow method.
func (u *domainStrippingIdentity) Allow(ctx context.Context, acl []string) (bool, error) {
	acl1 := make([]string, len(acl))
	for i, name := range acl {
		if !strings.Contains(name, "@") {
			acl1[i] = name + u.domain
		} else {
			acl1[i] = name
		}
	}
	ok, err := u.Identity.Allow(ctx, acl1)
	if err != nil {
		return false, errgo.Mask(err)
	}
	if ok {
		return true, nil
	}
	// We were denied access with the suffix added, but perhaps
	// the identity manager isn't yet adding suffixes - we still
	// want it to work in that case, so try without the added
	// suffixes.
	ok, err = u.Identity.Allow(ctx, acl)
	if err != nil {
		return false, errgo.Mask(err)
	}
	return ok, nil
}