// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 package localdb import ( "bytes" "context" "fmt" "html/template" "git.arvados.org/arvados.git/lib/controller/rpc" "git.arvados.org/arvados.git/sdk/go/arvados" "git.arvados.org/arvados.git/sdk/go/ctxlog" "github.com/sirupsen/logrus" ) type testLoginController struct { Cluster *arvados.Cluster Parent *Conn } func (ctrl *testLoginController) Logout(ctx context.Context, opts arvados.LogoutOptions) (arvados.LogoutResponse, error) { return logout(ctx, ctrl.Cluster, opts) } func (ctrl *testLoginController) Login(ctx context.Context, opts arvados.LoginOptions) (arvados.LoginResponse, error) { tmpl, err := template.New("form").Parse(loginform) if err != nil { return arvados.LoginResponse{}, err } var buf bytes.Buffer err = tmpl.Execute(&buf, opts) if err != nil { return arvados.LoginResponse{}, err } return arvados.LoginResponse{HTML: buf}, nil } func (ctrl *testLoginController) UserAuthenticate(ctx context.Context, opts arvados.UserAuthenticateOptions) (arvados.APIClientAuthorization, error) { for username, user := range ctrl.Cluster.Login.Test.Users { if (opts.Username == username || opts.Username == user.Email) && opts.Password == user.Password { ctxlog.FromContext(ctx).WithFields(logrus.Fields{ "username": username, "email": user.Email, }).Debug("test authentication succeeded") return ctrl.Parent.CreateAPIClientAuthorization(ctx, ctrl.Cluster.SystemRootToken, rpc.UserSessionAuthInfo{ Username: username, Email: user.Email, }) } } return arvados.APIClientAuthorization{}, fmt.Errorf("authentication failed for user %q with password len=%d", opts.Username, len(opts.Password)) } const loginform = ` <!doctype html> <html> <head><title>Arvados test login</title> <script> async function authenticate(event) { event.preventDefault() document.getElementById('error').innerHTML = '' const resp = await fetch('/arvados/v1/users/authenticate', { method: 'POST', mode: 'same-origin', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ username: document.getElementById('username').value, password: document.getElementById('password').value, }), }) if (!resp.ok) { document.getElementById('error').innerHTML = '<p>Authentication failed.</p><p>The "test login" users are defined in Clusters.[ClusterID].Login.Test.Users section of config.yml</p><p>If you are using arvbox, use "arvbox adduser" to add users.</p>' return } var redir = document.getElementById('return_to').value if (redir.indexOf('?') > 0) { redir += '&' } else { redir += '?' } const respj = await resp.json() document.location = redir + "api_token=v2/" + respj.uuid + "/" + respj.api_token } </script> </head> <body> <h3>Arvados test login</h3> <form method="POST"> <input id="return_to" type="hidden" name="return_to" value="{{.ReturnTo}}"> username <input id="username" type="text" name="username" autofocus size=16> password <input id="password" type="password" name="password" size=16> <input type="submit" value="Log in"> <br> <p id="error"></p> </form> </body> <script> document.getElementsByTagName('form')[0].onsubmit = authenticate </script> </html> `