~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/user/login.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package user
 
5
 
 
6
import (
 
7
        "github.com/juju/cmd"
 
8
        "github.com/juju/errors"
 
9
        "github.com/juju/names"
 
10
        "gopkg.in/macaroon.v1"
 
11
 
 
12
        "github.com/juju/juju/api/usermanager"
 
13
        "github.com/juju/juju/cmd/modelcmd"
 
14
        "github.com/juju/juju/juju"
 
15
        "github.com/juju/juju/jujuclient"
 
16
)
 
17
 
 
18
const loginDoc = `
 
19
Log in to the controller.
 
20
 
 
21
After logging in successfully, the client system will
 
22
be updated such that any previously recorded password
 
23
will be removed from disk, and a temporary, time-limited
 
24
credential written in its place. Once the credential
 
25
expires, you will be prompted to run "juju login" again.
 
26
 
 
27
Examples:
 
28
  # Log in as the current user for the controller.
 
29
  juju login
 
30
 
 
31
  # Log in as the user "bob".
 
32
  juju login bob
 
33
 
 
34
`
 
35
 
 
36
// NewLoginCommand returns a new cmd.Command to handle "juju login".
 
37
func NewLoginCommand() cmd.Command {
 
38
        return modelcmd.WrapController(&loginCommand{
 
39
                newLoginAPI: func(args juju.NewAPIConnectionParams) (LoginAPI, error) {
 
40
                        api, err := juju.NewAPIConnection(args)
 
41
                        if err != nil {
 
42
                                return nil, errors.Trace(err)
 
43
                        }
 
44
                        return usermanager.NewClient(api), nil
 
45
                },
 
46
        })
 
47
}
 
48
 
 
49
// loginCommand changes the password for a user.
 
50
type loginCommand struct {
 
51
        modelcmd.ControllerCommandBase
 
52
        newLoginAPI func(juju.NewAPIConnectionParams) (LoginAPI, error)
 
53
        User        string
 
54
}
 
55
 
 
56
// Info implements Command.Info.
 
57
func (c *loginCommand) Info() *cmd.Info {
 
58
        return &cmd.Info{
 
59
                Name:    "login",
 
60
                Args:    "[username]",
 
61
                Purpose: "logs in to the controller",
 
62
                Doc:     loginDoc,
 
63
        }
 
64
}
 
65
 
 
66
// Init implements Command.Init.
 
67
func (c *loginCommand) Init(args []string) error {
 
68
        var err error
 
69
        c.User, err = cmd.ZeroOrOneArgs(args)
 
70
        if err != nil {
 
71
                return errors.Trace(err)
 
72
        }
 
73
        return nil
 
74
}
 
75
 
 
76
// LoginAPI provides the API methods that the login command uses.
 
77
type LoginAPI interface {
 
78
        CreateLocalLoginMacaroon(names.UserTag) (*macaroon.Macaroon, error)
 
79
        Close() error
 
80
}
 
81
 
 
82
// Run implements Command.Run.
 
83
func (c *loginCommand) Run(ctx *cmd.Context) error {
 
84
        var accountName string
 
85
        var userTag names.UserTag
 
86
        controllerName := c.ControllerName()
 
87
        store := c.ClientStore()
 
88
        if c.User != "" {
 
89
                if !names.IsValidUserName(c.User) {
 
90
                        return errors.NotValidf("user name %q", c.User)
 
91
                }
 
92
                userTag = names.NewUserTag(c.User)
 
93
                accountName = userTag.Canonical()
 
94
        } else {
 
95
                var err error
 
96
                accountName, err = store.CurrentAccount(controllerName)
 
97
                if err != nil {
 
98
                        return errors.Trace(err)
 
99
                }
 
100
                userTag = names.NewUserTag(accountName)
 
101
        }
 
102
        accountDetails, err := store.AccountByName(controllerName, accountName)
 
103
        if err != nil && !errors.IsNotFound(err) {
 
104
                return errors.Trace(err)
 
105
        }
 
106
 
 
107
        // Read password from the terminal, and attempt to log in using that.
 
108
        password, err := readAndConfirmPassword(ctx)
 
109
        if err != nil {
 
110
                return errors.Trace(err)
 
111
        }
 
112
        params, err := c.NewAPIConnectionParams(store, controllerName, "", "")
 
113
        if err != nil {
 
114
                return errors.Trace(err)
 
115
        }
 
116
        if accountDetails != nil {
 
117
                accountDetails.Password = password
 
118
        } else {
 
119
                accountDetails = &jujuclient.AccountDetails{
 
120
                        User:     accountName,
 
121
                        Password: password,
 
122
                }
 
123
        }
 
124
        params.AccountDetails = accountDetails
 
125
        api, err := c.newLoginAPI(params)
 
126
        if err != nil {
 
127
                return errors.Annotate(err, "creating API connection")
 
128
        }
 
129
        defer api.Close()
 
130
 
 
131
        // Create a new local login macaroon, and update the account details
 
132
        // in the client store, removing the recorded password (if any) and
 
133
        // storing the macaroon.
 
134
        macaroon, err := api.CreateLocalLoginMacaroon(userTag)
 
135
        if err != nil {
 
136
                return errors.Annotate(err, "failed to create a temporary credential")
 
137
        }
 
138
        macaroonJSON, err := macaroon.MarshalJSON()
 
139
        if err != nil {
 
140
                return errors.Annotate(err, "marshalling temporary credential to JSON")
 
141
        }
 
142
        accountDetails.Password = ""
 
143
        accountDetails.Macaroon = string(macaroonJSON)
 
144
        if err := store.UpdateAccount(controllerName, accountName, *accountDetails); err != nil {
 
145
                return errors.Annotate(err, "failed to record temporary credential")
 
146
        }
 
147
        ctx.Infof("You are now logged in to %q as %q.", controllerName, accountName)
 
148
        return nil
 
149
}