github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/doc/logging-in-to-the-apiserver.txt (about) 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 environment manager and user manager 11 facades. This allows the user to change their password, create environments 12 and list the environments 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 state server environment - the original one 21 and only environment that would exist before the Juju Environment 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 - "/environment/:envuuid/api" -> srv.apiHandler 38 - "/" -> srv.apiHandler 39 40 The apiHandler creates a go routine for handling the socket connection, and 41 extracts the envuuid from the path, and calls the (*Server).serveConn method. 42 43 serveConn validates the environment UUID and gets an appropiate *state.State 44 for the environment specified. An empty environment UUID is treated as the 45 state server environment here. One thing that will need to change is passing 46 through whether or not we were given an environment 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 envUUID 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 envuuid 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, envUUID 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 envUUID 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