~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/api/usermanager/client.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package usermanager
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "strings"
 
9
 
 
10
        "gopkg.in/macaroon.v1"
 
11
 
 
12
        "github.com/juju/errors"
 
13
        "github.com/juju/loggo"
 
14
        "gopkg.in/juju/names.v2"
 
15
 
 
16
        "github.com/juju/juju/api/base"
 
17
        "github.com/juju/juju/api/modelmanager"
 
18
        "github.com/juju/juju/apiserver/params"
 
19
)
 
20
 
 
21
var logger = loggo.GetLogger("juju.api.usermanager")
 
22
 
 
23
// Client provides methods that the Juju client command uses to interact
 
24
// with users stored in the Juju Server.
 
25
type Client struct {
 
26
        base.ClientFacade
 
27
        facade base.FacadeCaller
 
28
}
 
29
 
 
30
// NewClient creates a new `Client` based on an existing authenticated API
 
31
// connection.
 
32
func NewClient(st base.APICallCloser) *Client {
 
33
        frontend, backend := base.NewClientFacade(st, "UserManager")
 
34
        return &Client{ClientFacade: frontend, facade: backend}
 
35
}
 
36
 
 
37
// AddUser creates a new local user in the controller, sharing with that user any specified models.
 
38
func (c *Client) AddUser(
 
39
        username, displayName, password, access string, modelUUIDs ...string,
 
40
) (_ names.UserTag, secretKey []byte, _ error) {
 
41
        if !names.IsValidUser(username) {
 
42
                return names.UserTag{}, nil, fmt.Errorf("invalid user name %q", username)
 
43
        }
 
44
        modelTags := make([]string, len(modelUUIDs))
 
45
        for i, uuid := range modelUUIDs {
 
46
                modelTags[i] = names.NewModelTag(uuid).String()
 
47
        }
 
48
 
 
49
        var accessPermission params.UserAccessPermission
 
50
        var err error
 
51
        if len(modelTags) > 0 {
 
52
                accessPermission, err = modelmanager.ParseModelAccess(access)
 
53
                if err != nil {
 
54
                        return names.UserTag{}, nil, errors.Trace(err)
 
55
                }
 
56
        }
 
57
 
 
58
        userArgs := params.AddUsers{
 
59
                Users: []params.AddUser{{
 
60
                        Username:        username,
 
61
                        DisplayName:     displayName,
 
62
                        Password:        password,
 
63
                        SharedModelTags: modelTags,
 
64
                        ModelAccess:     accessPermission}},
 
65
        }
 
66
        var results params.AddUserResults
 
67
        err = c.facade.FacadeCall("AddUser", userArgs, &results)
 
68
        if err != nil {
 
69
                return names.UserTag{}, nil, errors.Trace(err)
 
70
        }
 
71
        if count := len(results.Results); count != 1 {
 
72
                logger.Errorf("expected 1 result, got %#v", results)
 
73
                return names.UserTag{}, nil, errors.Errorf("expected 1 result, got %d", count)
 
74
        }
 
75
        result := results.Results[0]
 
76
        if result.Error != nil {
 
77
                return names.UserTag{}, nil, errors.Trace(result.Error)
 
78
        }
 
79
        tag, err := names.ParseUserTag(result.Tag)
 
80
        if err != nil {
 
81
                return names.UserTag{}, nil, errors.Trace(err)
 
82
        }
 
83
        return tag, result.SecretKey, nil
 
84
}
 
85
 
 
86
func (c *Client) userCall(username string, methodCall string) error {
 
87
        if !names.IsValidUser(username) {
 
88
                return errors.Errorf("%q is not a valid username", username)
 
89
        }
 
90
        tag := names.NewUserTag(username)
 
91
 
 
92
        var results params.ErrorResults
 
93
        args := params.Entities{
 
94
                []params.Entity{{tag.String()}},
 
95
        }
 
96
        err := c.facade.FacadeCall(methodCall, args, &results)
 
97
        if err != nil {
 
98
                return errors.Trace(err)
 
99
        }
 
100
        return results.OneError()
 
101
}
 
102
 
 
103
// DisableUser disables a user.  If the user is already disabled, the action
 
104
// is considered a success.
 
105
func (c *Client) DisableUser(username string) error {
 
106
        return c.userCall(username, "DisableUser")
 
107
}
 
108
 
 
109
// EnableUser enables a users.  If the user is already enabled, the action is
 
110
// considered a success.
 
111
func (c *Client) EnableUser(username string) error {
 
112
        return c.userCall(username, "EnableUser")
 
113
}
 
114
 
 
115
// RemoveUser deletes a user. That is it permanently removes the user, while
 
116
// retaining the record of the user to maintain provenance.
 
117
func (c *Client) RemoveUser(username string) error {
 
118
        return c.userCall(username, "RemoveUser")
 
119
}
 
120
 
 
121
// IncludeDisabled is a type alias to avoid bare true/false values
 
122
// in calls to the client method.
 
123
type IncludeDisabled bool
 
124
 
 
125
var (
 
126
        // ActiveUsers indicates to only return active users.
 
127
        ActiveUsers IncludeDisabled = false
 
128
        // AllUsers indicates that both enabled and disabled users should be
 
129
        // returned.
 
130
        AllUsers IncludeDisabled = true
 
131
)
 
132
 
 
133
// UserInfo returns information about the specified users.  If no users are
 
134
// specified, the call should return all users.  If includeDisabled is set to
 
135
// ActiveUsers, only enabled users are returned.
 
136
func (c *Client) UserInfo(usernames []string, all IncludeDisabled) ([]params.UserInfo, error) {
 
137
        var results params.UserInfoResults
 
138
        var entities []params.Entity
 
139
        for _, username := range usernames {
 
140
                if !names.IsValidUser(username) {
 
141
                        return nil, errors.Errorf("%q is not a valid username", username)
 
142
                }
 
143
                tag := names.NewUserTag(username)
 
144
                entities = append(entities, params.Entity{Tag: tag.String()})
 
145
        }
 
146
        args := params.UserInfoRequest{
 
147
                Entities:        entities,
 
148
                IncludeDisabled: bool(all),
 
149
        }
 
150
        err := c.facade.FacadeCall("UserInfo", args, &results)
 
151
        if err != nil {
 
152
                return nil, errors.Trace(err)
 
153
        }
 
154
        // Only need to look for errors if users were explicitly specified, because
 
155
        // if we didn't ask for any, we should get all, and we shouldn't get any
 
156
        // errors for listing all.  We care here because we index into the users
 
157
        // slice.
 
158
        if len(results.Results) == len(usernames) {
 
159
                var errorStrings []string
 
160
                for i, result := range results.Results {
 
161
                        if result.Error != nil {
 
162
                                annotated := errors.Annotate(result.Error, usernames[i])
 
163
                                errorStrings = append(errorStrings, annotated.Error())
 
164
                        }
 
165
                }
 
166
                if len(errorStrings) > 0 {
 
167
                        return nil, errors.New(strings.Join(errorStrings, ", "))
 
168
                }
 
169
        }
 
170
        info := []params.UserInfo{}
 
171
        for i, result := range results.Results {
 
172
                if result.Result == nil {
 
173
                        return nil, errors.Errorf("unexpected nil result at position %d", i)
 
174
                }
 
175
                info = append(info, *result.Result)
 
176
        }
 
177
        return info, nil
 
178
}
 
179
 
 
180
// SetPassword changes the password for the specified user.
 
181
func (c *Client) SetPassword(username, password string) error {
 
182
        if !names.IsValidUser(username) {
 
183
                return errors.Errorf("%q is not a valid username", username)
 
184
        }
 
185
        tag := names.NewUserTag(username)
 
186
        args := params.EntityPasswords{
 
187
                Changes: []params.EntityPassword{{
 
188
                        Tag:      tag.String(),
 
189
                        Password: password}},
 
190
        }
 
191
        var results params.ErrorResults
 
192
        err := c.facade.FacadeCall("SetPassword", args, &results)
 
193
        if err != nil {
 
194
                return err
 
195
        }
 
196
        return results.OneError()
 
197
}
 
198
 
 
199
// CreateLocalLoginMacaroon creates a local login macaroon for the
 
200
// authenticated user.
 
201
func (c *Client) CreateLocalLoginMacaroon(tag names.UserTag) (*macaroon.Macaroon, error) {
 
202
        args := params.Entities{Entities: []params.Entity{{tag.String()}}}
 
203
        var results params.MacaroonResults
 
204
        if err := c.facade.FacadeCall("CreateLocalLoginMacaroon", args, &results); err != nil {
 
205
                return nil, errors.Trace(err)
 
206
        }
 
207
        if n := len(results.Results); n != 1 {
 
208
                logger.Errorf("expected 1 result, got %#v", results)
 
209
                return nil, errors.Errorf("expected 1 result, got %d", n)
 
210
        }
 
211
        result := results.Results[0]
 
212
        if result.Error != nil {
 
213
                return nil, errors.Trace(result.Error)
 
214
        }
 
215
        return result.Result, nil
 
216
}