github.com/wostzone/hub/auth@v0.0.0-20220118060317-7bb375743b17/pkg/authservice/AuthService.go (about) 1 // Package authservice to serve a REST api for authentication and token refresh 2 package authservice 3 4 import ( 5 "crypto/ecdsa" 6 "crypto/tls" 7 "crypto/x509" 8 "fmt" 9 "io/ioutil" 10 "net/http" 11 12 "github.com/gorilla/mux" 13 "github.com/sirupsen/logrus" 14 "github.com/wostzone/hub/auth/pkg/authenticate" 15 "github.com/wostzone/hub/auth/pkg/configstore" 16 "github.com/wostzone/hub/auth/pkg/unpwstore" 17 "github.com/wostzone/hub/lib/client/pkg/tlsclient" 18 "github.com/wostzone/hub/lib/serve/pkg/tlsserver" 19 ) 20 21 // PluginID of the service 22 const PluginID = "authservice" 23 24 // DefaultAuthServicePort to connect to the auth service 25 const DefaultAuthServicePort = 8881 26 27 // internal constant for appID route parameter 28 const appIDParam = "appid" 29 30 // AuthServiceConfig contains the service configuration 31 type AuthServiceConfig struct { 32 // Override of the server address from hub.yaml 33 Address string `yaml:"address"` 34 35 // Service listening port or 0 to use the default port 8881 36 Port uint `yaml:"port"` 37 38 // ClientID to identify this service as. Default is the pluginID 39 ClientID string `yaml:"clientID"` 40 41 // Enable the configuration store for authenticated users. A folder MUST be set. 42 ConfigStoreEnabled bool `yaml:"configStoreEnabled"` 43 44 // Set the config store folder. Required for enabling the config store 45 ConfigStoreFolder string `yaml:"configStoreFolder"` 46 47 // PasswordFile to read from. Use "" for default defined in 'unpwstore.DefaultPasswordFile' 48 PasswordFile string `yaml:"passwordFile"` 49 } 50 51 // AuthService for handling authentication and token refresh requests 52 // 1. Handle login requests and issue JWT tokens 53 // 2. Handle refresh requests and re-issue JWT tokens 54 // 3. Handle config requests to persist client configuration 55 // 56 type AuthService struct { 57 config AuthServiceConfig 58 configStore *configstore.ConfigStore 59 running bool 60 tlsServer *tlsserver.TLSServer 61 signingKey *ecdsa.PrivateKey 62 authenticator *authenticate.Authenticator 63 } 64 65 // EnableConfigStore listens for configuration store requests. 66 // URL is PUT/GET {server}/auth/config/{appID} 67 // storeFolder Folder to store user configuration files 68 func (srv *AuthService) EnableConfigStore(storeFolder string) { 69 srv.configStore = configstore.NewConfigStore(storeFolder) 70 err := srv.configStore.Open() 71 if err != nil { 72 logrus.Errorf("Failed opening user configuration store: %s", err) 73 return 74 } 75 76 srv.tlsServer.AddHandler(tlsclient.DefaultJWTConfigPath+"/{"+appIDParam+"}", srv.ServeConfig) 77 } 78 79 // ServeConfig serves or updates user configuration [GET/PUT] 80 func (srv *AuthService) ServeConfig(userID string, resp http.ResponseWriter, req *http.Request) { 81 logrus.Infof("AuthService.ServeConfig: userID=%s", userID) 82 appID := mux.Vars(req)[appIDParam] 83 if req.Method == http.MethodPut { 84 logrus.Warningf("ServeConfig, updated configuration for user '%s'", userID) 85 payload, err := ioutil.ReadAll(req.Body) 86 if err != nil { 87 srv.tlsServer.WriteBadRequest(resp, "Missing payload") 88 return 89 } 90 _ = srv.configStore.Put(userID, appID, string(payload)) 91 } else if req.Method == http.MethodGet { 92 payload := srv.configStore.Get(userID, appID) 93 _, _ = resp.Write([]byte(payload)) 94 return 95 } else { 96 logrus.Warningf("ServeConfig, method %s not support for user %s", req.Method, userID) 97 srv.tlsServer.WriteBadRequest(resp, "Bad method "+req.Method) 98 return 99 } 100 } 101 102 // SetPassword for updating a user's password 103 func (srv *AuthService) SetPassword(userID, password string) error { 104 return srv.authenticator.SetPassword(userID, password) 105 } 106 107 // Start listening for login and refresh requests 108 func (srv *AuthService) Start() error { 109 var err error 110 111 // call me as often as you like, or is this an error? 112 if srv.running { 113 err := fmt.Errorf("AuthService is already running") 114 logrus.Error(err) 115 return err 116 } 117 pwStore := unpwstore.NewPasswordFileStore(srv.config.PasswordFile, srv.config.ClientID) 118 srv.authenticator = authenticate.NewAuthenticator(pwStore) 119 err = srv.authenticator.Start() 120 if err != nil { 121 return err 122 } 123 124 err = srv.tlsServer.Start() 125 if err != nil { 126 logrus.Errorf("AuthService.Start: Error starting authservice: %s", err) 127 return err 128 } 129 // add auth handlers 130 srv.tlsServer.EnableJwtAuth(&srv.signingKey.PublicKey) 131 srv.tlsServer.EnableJwtIssuer(srv.signingKey, srv.authenticator.VerifyUsernamePassword) 132 133 if srv.config.ConfigStoreEnabled && srv.config.ConfigStoreFolder != "" { 134 srv.EnableConfigStore(srv.config.ConfigStoreFolder) 135 } 136 srv.running = true 137 return nil 138 } 139 140 // Stop the authservice 141 func (srv *AuthService) Stop() { 142 if srv.running { 143 srv.running = false 144 srv.authenticator.Stop() 145 srv.tlsServer.Stop() 146 } 147 } 148 149 // NewJwtAuthService creates a new instance of a TLS authservice for JWT authentication. 150 // 151 // The signing key contains the key needed for JWT token generation and verification. 152 // For single signon the server certificate public key can be used for verification if the 153 // certificates are generated using the same key pair. 154 // 155 // config service configuration 156 // signingKey private/public key used to sign and verify JWT tokens. nil to use the server certificate keys. 157 // serverCert server own TLS certificate, signed with ecdsa keys 158 // caCert CA certificate to verify client certificates 159 // verifyUsernamePassword function of the password store to verify username/password 160 // This returns the authentication authservice instance. 161 func NewJwtAuthService( 162 config AuthServiceConfig, 163 signingKey *ecdsa.PrivateKey, 164 serverCert *tls.Certificate, 165 caCert *x509.Certificate) *AuthService { 166 167 if config.Port == 0 { 168 config.Port = DefaultAuthServicePort 169 } 170 if config.ClientID == "" { 171 config.ClientID = PluginID 172 } 173 174 // The TLS server authenticates a request. 175 tlsServer := tlsserver.NewTLSServer(config.Address, config.Port, serverCert, caCert) 176 177 if signingKey == nil { 178 signingKey = serverCert.PrivateKey.(*ecdsa.PrivateKey) 179 } 180 181 srv := AuthService{ 182 config: config, 183 tlsServer: tlsServer, 184 signingKey: signingKey, 185 } 186 return &srv 187 }