mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-03 02:39:52 -06:00
Add ocis idm resetpassword subcommand
This allows resetting the ocis admin user's password (when ocis is not running) when running with the builtin LDAP server. Fixes #4084
This commit is contained in:
8
changelog/unreleased/enhancment-admin-pwreset.md
Normal file
8
changelog/unreleased/enhancment-admin-pwreset.md
Normal file
@@ -0,0 +1,8 @@
|
||||
Enhancement: added command to reset administrator password
|
||||
|
||||
The new command `ocis idm resetpassword` allows to reset the administrator
|
||||
password when ocis is not running. So it is possible to recover setups
|
||||
where the admin password was lost.
|
||||
|
||||
https://github.com/owncloud/ocis/issues/4084
|
||||
https://github.com/owncloud/ocis/pull/4365
|
||||
24
docs/services/idm/admin_password_reset.md
Normal file
24
docs/services/idm/admin_password_reset.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Resetting a lost administrator password
|
||||
date: 2022-08-29:00:00+00:00
|
||||
weight: 10
|
||||
geekdocRepo: https://github.com/owncloud/ocis
|
||||
geekdocEditPath: edit/master/docs/services/idm
|
||||
geekdocFilePath: admin_password_reset.md
|
||||
geekdocCollapseSection: true
|
||||
---
|
||||
|
||||
## Resetting a lost administrator password
|
||||
By default, when using oCIS with the builtin IDM an ad generates the
|
||||
user `admin` (DN `uid=admin,ou=users,o=libregraph-idm`) if, for any
|
||||
reason, the password of that user is lost, it can be reset using
|
||||
the `resetpassword` sub-command:
|
||||
|
||||
```
|
||||
ocis idm resetpassword
|
||||
```
|
||||
|
||||
It will prompt for a new password and set the password of that user
|
||||
accordingly. Note: As this command is accessing the idm database directly
|
||||
will only work while ocis is not running and nothing else is accessing
|
||||
database.
|
||||
3
go.mod
3
go.mod
@@ -63,6 +63,7 @@ require (
|
||||
github.com/urfave/cli/v2 v2.11.1
|
||||
github.com/xhit/go-simple-mail/v2 v2.11.0
|
||||
go-micro.dev/v4 v4.8.0
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
go.opencensus.io v0.23.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.34.0
|
||||
go.opentelemetry.io/otel v1.9.0
|
||||
@@ -74,6 +75,7 @@ require (
|
||||
golang.org/x/image v0.0.0-20220321031419-a8550c1d254a
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035
|
||||
google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58
|
||||
google.golang.org/grpc v1.48.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
@@ -254,7 +256,6 @@ require (
|
||||
github.com/wk8/go-ordered-map v1.0.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.2 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.2 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.2 // indirect
|
||||
|
||||
1
go.sum
1
go.sum
@@ -1568,6 +1568,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
118
services/idm/pkg/command/resetpw.go
Normal file
118
services/idm/pkg/command/resetpw.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/libregraph/idm/pkg/ldbbolt"
|
||||
"github.com/libregraph/idm/server"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/services/idm/pkg/config"
|
||||
"github.com/owncloud/ocis/v2/services/idm/pkg/config/parser"
|
||||
"github.com/owncloud/ocis/v2/services/idm/pkg/logging"
|
||||
"github.com/urfave/cli/v2"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// ResetPassword is the entrypoint for the resetpassword command
|
||||
func ResetPassword(cfg *config.Config) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "resetpassword",
|
||||
Usage: fmt.Sprintf("Reset admin password"),
|
||||
Category: "password reset",
|
||||
Before: func(c *cli.Context) error {
|
||||
err := parser.ParseConfig(cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return err
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
logger := logging.Configure(cfg.Service.Name, cfg.Log)
|
||||
ctx, cancel := func() (context.Context, context.CancelFunc) {
|
||||
if cfg.Context == nil {
|
||||
return context.WithCancel(context.Background())
|
||||
}
|
||||
return context.WithCancel(cfg.Context)
|
||||
}()
|
||||
|
||||
defer cancel()
|
||||
return resetPassword(ctx, logger, cfg)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resetPassword(ctx context.Context, logger log.Logger, cfg *config.Config) error {
|
||||
servercfg := server.Config{
|
||||
Logger: log.LogrusWrap(logger.Logger),
|
||||
LDAPHandler: "boltdb",
|
||||
LDAPBaseDN: "o=libregraph-idm",
|
||||
|
||||
BoltDBFile: cfg.IDM.DatabasePath,
|
||||
}
|
||||
|
||||
adminUserDN := "uid=admin,ou=users," + servercfg.LDAPBaseDN
|
||||
fmt.Printf("Resetting password for user '%s'.\n", adminUserDN)
|
||||
if _, err := os.Stat(servercfg.BoltDBFile); errors.Is(err, os.ErrNotExist) {
|
||||
fmt.Fprintf(os.Stderr, "IDM database does not exist.\n")
|
||||
return err
|
||||
}
|
||||
|
||||
newPw, err := getPassword()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading password: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
bdb := &ldbbolt.LdbBolt{}
|
||||
|
||||
opts := bolt.Options{
|
||||
Timeout: 1 * time.Millisecond,
|
||||
}
|
||||
if err := bdb.Configure(servercfg.Logger, servercfg.LDAPBaseDN, servercfg.BoltDBFile, &opts); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to open database: '%s'. Please stop any running ocis/idm instance, as this tool requires exclusive access to the database.\n", err)
|
||||
return err
|
||||
}
|
||||
defer bdb.Close()
|
||||
|
||||
if err := bdb.Initialize(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pwRequest := ldap.NewPasswordModifyRequest(adminUserDN, "", newPw)
|
||||
if err := bdb.UpdatePassword(pwRequest); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to update admin password: %v\n", err)
|
||||
}
|
||||
fmt.Printf("Password for user '%s' updated.\n", adminUserDN)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPassword() (string, error) {
|
||||
fmt.Print("Enter new password: ")
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fmt.Println("")
|
||||
fmt.Print("Re-enter new password: ")
|
||||
bytePasswordVerify, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fmt.Println("")
|
||||
|
||||
password := string(bytePassword)
|
||||
passwordVerify := string(bytePasswordVerify)
|
||||
|
||||
if password != passwordVerify {
|
||||
return "", errors.New("Passwords do not match")
|
||||
}
|
||||
return password, nil
|
||||
}
|
||||
@@ -18,6 +18,7 @@ func GetCommands(cfg *config.Config) cli.Commands {
|
||||
Server(cfg),
|
||||
|
||||
// interaction with this service
|
||||
ResetPassword(cfg),
|
||||
|
||||
// infos about this service
|
||||
Health(cfg),
|
||||
|
||||
Reference in New Issue
Block a user