~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/doc/logging-in-to-the-apiserver.txt

  • 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
Logging in to the API Server
 
2
============================
 
3
 
 
4
This document is being written because every time I need to look at how
 
5
logging in to the API server works, I have to step through all the code and
 
6
remind myself. Once I have done that, everything seems obvious and not worth
 
7
writing down... until next time I need to think about the login process.
 
8
 
 
9
Intended work is to add the ability to have a user log in to the root of the
 
10
API server in order to get access to the model manager and user manager
 
11
facades. This allows the user to change their password, create models
 
12
and list the models that they are able to connect to.
 
13
 
 
14
The intended way that this is going to work is that the API client code will
 
15
attempt to login to the server using a versioned login command. There is
 
16
already a login-v1 that introduced new return values and a reauth request
 
17
field. We will build on that behaviour to add a login-v2. If and only if the
 
18
version 2 login is used the facades that are available at the apiserver will
 
19
be restricted.  Logging in using version 1 or the original will continue to
 
20
act as if you are logging into the controller model - the original one
 
21
and only model that would exist before the Juju Model Server work.
 
22
 
 
23
This work then needs to look at the API connection workflow from both ends,
 
24
the API client side, and the server side.
 
25
 
 
26
apiserver.Server
 
27
----------------
 
28
 
 
29
apiserver.go
 
30
 
 
31
Server struct has a map of adminApiFactories. This currently has keys of
 
32
0 and 1.  We will need to add a 2 here.
 
33
 
 
34
The Server instance is created with NewServer, and listens on the API port.
 
35
 
 
36
The incoming socket connection is handled inside the (*Server).run method.
 
37
 - "/model/:modeluuid/api" -> srv.apiHandler
 
38
 - "/" -> srv.apiHandler
 
39
 
 
40
The apiHandler creates a go routine for handling the socket connection, and
 
41
extracts the modelUUID from the path, and calls the (*Server).serveConn method.
 
42
 
 
43
serveConn validates the model UUID and gets an appropiate *state.State
 
44
for the model specified.  An empty model UUID is treated as the
 
45
controller model here.  One thing that will need to change is passing
 
46
through whether or not we were given an model UUID, as this is the last
 
47
place that cares, but we will need to know later when the appropriate login
 
48
method is called. The various admin API instances are created here and passed
 
49
through to the newAnonRoot object.  This is passed in as the method finder for
 
50
the websocket connection.
 
51
 
 
52
root.go
 
53
 
 
54
newAnonRoot only responds to calls on the "Admin" rootName.  The version of
 
55
the FindMethod is used to determine whether the version 0 or 1 login API is
 
56
used.
 
57
 
 
58
The Login methods on the adminV0 and adminV1 instances call into the doLogin
 
59
method.  It is here where we want to wrap the authedApi with something that
 
60
limits the rootName objects that can be called.  In order to do this, we need
 
61
to pass the modelUUID from the path (remember this is either a valid uuid or the
 
62
empty string), and the version of the login command used.
 
63
 
 
64
In order to get the modelUUID from the path into the Login method, we need to
 
65
capture it in *Server.serveConn, where it is passed in as an argument.  We
 
66
should pass it through to the newApiHandler function and store it on the
 
67
apiHandler struct.  This handler is passed through as an arg to the
 
68
newAnonRoot, and to the factory methods for the admin APIs.
 
69
 
 
70
 
 
71
Implementation Notes:
 
72
 
 
73
The login process for both v0 and v1 logins are handled in the method
 
74
*admin.doLogin (in admin.go).  The method *Conn.ServeFinder on the *rpc.Conn
 
75
attribute of the apiHandler is initially given the anonymous root here:
 
76
 
 
77
```go
 
78
func (srv *Server) serveConn(wsConn *websocket.Conn, reqNotifier *requestNotifier, modelUUID string) error {
 
79
        // ...
 
80
                conn.ServeFinder(newAnonRoot(h, adminApis), serverError)
 
81
        // ...
 
82
```
 
83
 
 
84
If login is successful, the doLogin method changes out the method finder that
 
85
is used for the RPC connection just before the end of the return statement at
 
86
the end of the method.
 
87
 
 
88
```go
 
89
        // a *admin
 
90
        //
 
91
        // root is `*apiHander` from the admin struct.
 
92
        a.root.rpcConn.ServeFinder(authedApi, serverError)
 
93
```
 
94
 
 
95
In order to supply a restricted api at the root, the doLogin method will need
 
96
to take a version number.  Just before we replace the method finder for the
 
97
RPC connection, we check the version number and the modelUUID of the api
 
98
handler, and wrap the authedApi in a restricted root method finder implemented
 
99
in a similar manner to the upgradingRoot method finder.
 
100