Commit 12462a89 authored by shammash's avatar shammash

Report last login

Add filter to report last login information for a service to usermetadb.

The filter is active when the `enable_last_login_reporting` option is
set.
Signed-off-by: shammash's avatarshammash <shammash@autistici.org>
parent 08340119
Pipeline #2214 passed with stage
in 25 seconds
......@@ -116,6 +116,8 @@ Each service definition is a dictionary with the following attributes:
only for interactive services)
* `enforce_2fa` is a boolean flag that, when true, will disable
non-2FA logins for this service
* `enable_last_login_reporting` is a boolean flag that enables last login
reporting to usermetadb
* `enable_device_tracking` is a boolean flag that enables device
tracking for this service (assuming the client provides device
information)
......
......@@ -203,6 +203,17 @@ func createService(config *Config, sc *ServiceConfig, backends map[string]userBa
}
}
if sc.EnableLastLoginReporting {
if config.UserMetaDBConfig == nil {
return nil, errors.New("usermetadb config is missing")
}
llr, err := newLastLoginFilter(config.UserMetaDBConfig)
if err != nil {
return nil, err
}
s.filters = append(s.filters, llr)
}
// Enabling device tracking also enables user activity
// logging.
if sc.EnableDeviceTracking {
......
......@@ -19,11 +19,12 @@ type BackendSpec struct {
// ServiceConfig defines the authentication backends for a service.
type ServiceConfig struct {
BackendSpecs []*BackendSpec `yaml:"backends"`
ChallengeResponse bool `yaml:"challenge_response"`
Enforce2FA bool `yaml:"enforce_2fa"`
EnableDeviceTracking bool `yaml:"enable_device_tracking"`
Ratelimits []string `yaml:"rate_limits"`
BackendSpecs []*BackendSpec `yaml:"backends"`
ChallengeResponse bool `yaml:"challenge_response"`
Enforce2FA bool `yaml:"enforce_2fa"`
EnableLastLoginReporting bool `yaml:"enable_last_login_reporting"`
EnableDeviceTracking bool `yaml:"enable_device_tracking"`
Ratelimits []string `yaml:"rate_limits"`
}
// Config for the authentication server.
......
package server
import (
"context"
"log"
"time"
"git.autistici.org/ai3/go-common/clientutil"
"git.autistici.org/id/auth"
"git.autistici.org/id/usermetadb"
"git.autistici.org/id/usermetadb/client"
)
type setLastLoginClient interface {
SetLastLogin(context.Context, string, *usermetadb.LastLoginEntry) error
}
type lastloginFilter struct {
client setLastLoginClient
}
func newLastLoginFilter(config *clientutil.BackendConfig) (*lastloginFilter, error) {
c, err := client.New(config)
if err != nil {
return nil, err
}
return &lastloginFilter{c}, nil
}
var lastloginTimeout = 30 * time.Second
func (f *lastloginFilter) Filter(user *User, req *auth.Request, resp *auth.Response) *auth.Response {
if resp.Status != auth.StatusOK {
return resp
}
entry := usermetadb.LastLoginEntry{
Timestamp: time.Now(),
Username: user.Name,
Service: req.Service,
}
// Make the log RPC in the background, no need to wait for it to complete.
go func() {
ctx, cancel := context.WithTimeout(context.Background(), lastloginTimeout)
defer cancel()
if err := f.client.SetLastLogin(ctx, user.Shard, &entry); err != nil {
log.Printf("usermetadb.SetLastLogin error for %s: %v", user.Name, err)
}
}()
return resp
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment