diff options
| -rw-r--r-- | BREAKING.md | 10 | ||||
| -rw-r--r-- | README.md | 3 | ||||
| -rwxr-xr-x | cmd/authelia-scripts/authelia-scripts | 2 | ||||
| -rwxr-xr-x | cmd/authelia-scripts/main.go | 2 | ||||
| -rw-r--r-- | cmd/authelia/main.go | 2 | ||||
| -rw-r--r-- | internal/commands/migration.go | 80 | ||||
| -rw-r--r-- | internal/commands/migration_local.go | 153 | ||||
| -rw-r--r-- | internal/commands/migration_mongo.go | 186 | 
8 files changed, 5 insertions, 433 deletions
diff --git a/BREAKING.md b/BREAKING.md index bd37586b1..5686926c3 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -54,16 +54,10 @@ supported by Authelia v4.  Example of usage:  ```  # Migrate a local database into the targeted database defined in config-v4.yml with Docker -docker run --rm -v /path/to/config-v4.yml:/config.yml -v /old/db/path:/db authelia/authelia authelia migrate local --config=/config.yml --db-path=/db +docker run --rm -v /path/to/config-v4.yml:/config.yml -v /old/db/path:/db authelia/authelia:4.14.2 authelia migrate local --config=/config.yml --db-path=/db  # Migrate a mongo database into the targeted database defined in config-v4.yml with Docker -docker run --rm -v /path/to/config-v4.yml:/config.yml authelia/authelia authelia migrate mongo --config=/config.yml --url=mongodb://myuser:mypassword@mymongo:27017 --database=authelia - -# Migrate a local database into the targeted database defined in config-v4.yml -authelia-scripts migrate local --config=/path/to/config-v4.yml --db-path=/old/db/path - -# Migrate a mongo database into the targeted database defined in config-v4.yml -authelia-scripts migrate mongo --config=/path/to/config-v4.yml --url=mongodb://myuser:mypassword@mymongo:27017 --database=authelia +docker run --rm -v /path/to/config-v4.yml:/config.yml authelia/authelia:4.14.2 authelia migrate mongo --config=/config.yml --url=mongodb://myuser:mypassword@mymongo:27017 --database=authelia  ```  Those commands migrate TOTP secrets, U2F devices, authentication traces and user preferences so @@ -28,9 +28,6 @@ The architecture is shown in the diagram below.    <img src="./docs/images/archi.png"/>  </p> -**BREAKING NEWS: Authelia v4 has been released! -Please read BREAKING.md if you want to migrate from v3 to v4. Otherwise, start fresh in v4 and enjoy!** -  **Authelia** can be installed as a standalone service from the [AUR](https://aur.archlinux.org/packages/authelia/), using a [Static binary](https://github.com/authelia/authelia/releases/latest), [Docker]  or can also be deployed easily on [Kubernetes] leveraging ingress controllers and ingress configuration. diff --git a/cmd/authelia-scripts/authelia-scripts b/cmd/authelia-scripts/authelia-scripts index 2bf8bb3ad..d9f522641 100755 --- a/cmd/authelia-scripts/authelia-scripts +++ b/cmd/authelia-scripts/authelia-scripts @@ -1,3 +1,3 @@  #!/bin/bash -go run -tags migration cmd/authelia-scripts/*.go $*
\ No newline at end of file +go run cmd/authelia-scripts/*.go $*
\ No newline at end of file diff --git a/cmd/authelia-scripts/main.go b/cmd/authelia-scripts/main.go index 19171fc31..1d50fd03b 100755 --- a/cmd/authelia-scripts/main.go +++ b/cmd/authelia-scripts/main.go @@ -130,7 +130,7 @@ func main() {  		cobraCommands = append(cobraCommands, command)  	} -	cobraCommands = append(cobraCommands, commands.HashPasswordCmd, commands.MigrateCmd) +	cobraCommands = append(cobraCommands, commands.HashPasswordCmd)  	rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Set the log level for the command")  	rootCmd.AddCommand(cobraCommands...) diff --git a/cmd/authelia/main.go b/cmd/authelia/main.go index 0b02b5edd..9b93cc38f 100644 --- a/cmd/authelia/main.go +++ b/cmd/authelia/main.go @@ -130,7 +130,7 @@ func main() {  		},  	} -	rootCmd.AddCommand(versionCmd, commands.MigrateCmd, commands.HashPasswordCmd) +	rootCmd.AddCommand(versionCmd, commands.HashPasswordCmd)  	rootCmd.AddCommand(commands.CertificatesCmd)  	if err := rootCmd.Execute(); err != nil {  		log.Fatal(err) diff --git a/internal/commands/migration.go b/internal/commands/migration.go deleted file mode 100644 index 7f610be4f..000000000 --- a/internal/commands/migration.go +++ /dev/null @@ -1,80 +0,0 @@ -package commands - -import ( -	"encoding/base64" -	"strings" - -	"github.com/spf13/cobra" - -	"github.com/authelia/authelia/internal/configuration" -	"github.com/authelia/authelia/internal/storage" -) - -// MigrateCmd migration helper command. -var MigrateCmd *cobra.Command - -func init() { -	MigrateCmd = &cobra.Command{ -		Use:   "migrate", -		Short: "helper function to migrate from v3 to v4", -	} -	MigrateCmd.AddCommand(MigrateLocalCmd, MigrateMongoCmd) -} - -// TOTPSecretsV3 one entry of TOTP secrets in v3. -type TOTPSecretsV3 struct { -	UserID string `json:"userId"` -	Secret struct { -		Base32 string `json:"base32"` -	} `json:"secret"` -} - -// U2FDeviceHandleV3 one entry of U2F device handle in v3. -type U2FDeviceHandleV3 struct { -	UserID       string `json:"userId"` -	Registration struct { -		KeyHandle string `json:"keyHandle"` -		PublicKey string `json:"publicKey"` -	} `json:"registration"` -} - -// PreferencesV3 one entry of preferences in v3. -type PreferencesV3 struct { -	UserID string `json:"userId"` -	Method string `json:"method"` -} - -// AuthenticationTraceV3 one authentication trace in v3. -type AuthenticationTraceV3 struct { -	UserID     string `json:"userId"` -	Successful bool   `json:"isAuthenticationSuccessful"` -	Date       struct { -		Date int64 `json:"$$date"` -	} `json:"date"` -} - -func decodeWebsafeBase64(s string) ([]byte, error) { -	s = strings.ReplaceAll(s, "_", "/") -	s = strings.ReplaceAll(s, "-", "+") - -	for len(s)%4 != 0 { -		s += "=" -	} - -	return base64.StdEncoding.DecodeString(s) -} - -func createDBProvider(configurationPath string) storage.Provider { -	config, _ := configuration.Read(configurationPath) - -	var dbProvider storage.Provider -	if config.Storage.Local != nil { -		dbProvider = storage.NewSQLiteProvider(config.Storage.Local.Path) -	} else if config.Storage.MySQL != nil { -		dbProvider = storage.NewMySQLProvider(*config.Storage.MySQL) -	} else if config.Storage.PostgreSQL != nil { -		dbProvider = storage.NewPostgreSQLProvider(*config.Storage.PostgreSQL) -	} - -	return dbProvider -} diff --git a/internal/commands/migration_local.go b/internal/commands/migration_local.go deleted file mode 100644 index a6e31ea42..000000000 --- a/internal/commands/migration_local.go +++ /dev/null @@ -1,153 +0,0 @@ -package commands - -import ( -	"bufio" -	"encoding/json" -	"log" -	"os" -	"path" -	"time" - -	"github.com/spf13/cobra" - -	"github.com/authelia/authelia/internal/models" -	"github.com/authelia/authelia/internal/storage" -) - -var configurationPath string -var localDatabasePath string - -// MigrateLocalCmd migration command. -var MigrateLocalCmd = &cobra.Command{ -	Use:   "localdb", -	Short: "Migrate data from v3 local database into database configured in v4 configuration file", -	Run:   migrateLocal, -} - -func init() { -	MigrateLocalCmd.PersistentFlags().StringVarP(&localDatabasePath, "db-path", "p", "", "The path to the v3 local database") -	MigrateLocalCmd.MarkPersistentFlagRequired("db-path") //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. - -	MigrateLocalCmd.PersistentFlags().StringVarP(&configurationPath, "config", "c", "", "The configuration file of Authelia v4") -	MigrateLocalCmd.MarkPersistentFlagRequired("config") //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. -} - -// migrateLocal data from v3 to v4. -func migrateLocal(cmd *cobra.Command, args []string) { -	dbProvider := createDBProvider(configurationPath) - -	migrateLocalTOTPSecret(dbProvider) -	migrateLocalU2FSecret(dbProvider) -	migrateLocalPreferences(dbProvider) -	migrateLocalAuthenticationTraces(dbProvider) -	// We don't need to migrate identity tokens - -	log.Println("Migration done!") -} - -func migrateLocalTOTPSecret(dbProvider storage.Provider) { -	file, err := os.Open(path.Join(localDatabasePath, "totp_secrets")) -	if err != nil { -		log.Fatal(err) -	} -	defer file.Close() -	scanner := bufio.NewScanner(file) -	scanner.Split(bufio.ScanLines) - -	for scanner.Scan() { -		data := scanner.Text() - -		entry := TOTPSecretsV3{} -		json.Unmarshal([]byte(data), &entry) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. -		err := dbProvider.SaveTOTPSecret(entry.UserID, entry.Secret.Base32) - -		if err != nil { -			log.Fatal(err) -		} -	} -} - -func migrateLocalU2FSecret(dbProvider storage.Provider) { -	file, err := os.Open(path.Join(localDatabasePath, "u2f_registrations")) -	if err != nil { -		log.Fatal(err) -	} -	defer file.Close() -	scanner := bufio.NewScanner(file) -	scanner.Split(bufio.ScanLines) - -	for scanner.Scan() { -		data := scanner.Text() - -		entry := U2FDeviceHandleV3{} -		json.Unmarshal([]byte(data), &entry) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. - -		kH, err := decodeWebsafeBase64(entry.Registration.KeyHandle) - -		if err != nil { -			log.Fatal(err) -		} - -		pK, err := decodeWebsafeBase64(entry.Registration.PublicKey) - -		if err != nil { -			log.Fatal(err) -		} - -		err = dbProvider.SaveU2FDeviceHandle(entry.UserID, kH, pK) - -		if err != nil { -			log.Fatal(err) -		} -	} -} - -func migrateLocalPreferences(dbProvider storage.Provider) { -	file, err := os.Open(path.Join(localDatabasePath, "prefered_2fa_method")) //nolint:misspell -	if err != nil { -		log.Fatal(err) -	} -	defer file.Close() -	scanner := bufio.NewScanner(file) -	scanner.Split(bufio.ScanLines) - -	for scanner.Scan() { -		data := scanner.Text() - -		entry := PreferencesV3{} -		json.Unmarshal([]byte(data), &entry) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. -		err := dbProvider.SavePreferred2FAMethod(entry.UserID, entry.Method) - -		if err != nil { -			log.Fatal(err) -		} -	} -} - -func migrateLocalAuthenticationTraces(dbProvider storage.Provider) { -	file, err := os.Open(path.Join(localDatabasePath, "authentication_traces")) -	if err != nil { -		log.Fatal(err) -	} -	defer file.Close() -	scanner := bufio.NewScanner(file) -	scanner.Split(bufio.ScanLines) - -	for scanner.Scan() { -		data := scanner.Text() - -		entry := AuthenticationTraceV3{} -		json.Unmarshal([]byte(data), &entry) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. - -		attempt := models.AuthenticationAttempt{ -			Username:   entry.UserID, -			Successful: entry.Successful, -			Time:       time.Unix(entry.Date.Date/1000.0, 0), -		} -		err := dbProvider.AppendAuthenticationLog(attempt) - -		if err != nil { -			log.Fatal(err) -		} -	} -} diff --git a/internal/commands/migration_mongo.go b/internal/commands/migration_mongo.go deleted file mode 100644 index dd6dd865b..000000000 --- a/internal/commands/migration_mongo.go +++ /dev/null @@ -1,186 +0,0 @@ -package commands - -import ( -	"context" -	"log" -	"time" - -	"github.com/spf13/cobra" -	"go.mongodb.org/mongo-driver/bson" -	"go.mongodb.org/mongo-driver/mongo" -	"go.mongodb.org/mongo-driver/mongo/options" - -	"github.com/authelia/authelia/internal/models" -	"github.com/authelia/authelia/internal/storage" -) - -var mongoURL string -var mongoDatabase string - -// MigrateMongoCmd migration command. -var MigrateMongoCmd = &cobra.Command{ -	Use:   "mongo", -	Short: "Migrate data from v3 mongo database into database configured in v4 configuration file", -	Run:   migrateMongo, -} - -func init() { -	MigrateMongoCmd.PersistentFlags().StringVar(&mongoURL, "url", "", "The address to the mongo server") -	MigrateMongoCmd.MarkPersistentFlagRequired("url") //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. - -	MigrateMongoCmd.PersistentFlags().StringVar(&mongoDatabase, "database", "", "The mongo database") -	MigrateMongoCmd.MarkPersistentFlagRequired("database") //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. - -	MigrateMongoCmd.PersistentFlags().StringVarP(&configurationPath, "config", "c", "", "The configuration file of Authelia v4") -	MigrateMongoCmd.MarkPersistentFlagRequired("config") //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. -} - -func migrateMongo(cmd *cobra.Command, args []string) { -	dbProvider := createDBProvider(configurationPath) -	client, err := mongo.NewClient(options.Client().ApplyURI(mongoURL)) - -	if err != nil { -		log.Fatal(err) -	} - -	err = client.Connect(context.Background()) - -	if err != nil { -		log.Fatal(err) -	} - -	db := client.Database(mongoDatabase) - -	migrateMongoU2FDevices(db, dbProvider) -	migrateMongoTOTPDevices(db, dbProvider) -	migrateMongoPreferences(db, dbProvider) -	migrateMongoAuthenticationTraces(db, dbProvider) - -	log.Println("Migration done!") -} - -func migrateMongoU2FDevices(db *mongo.Database, dbProvider storage.Provider) { -	u2fCollection := db.Collection("u2f_registrations") - -	cur, err := u2fCollection.Find(context.Background(), bson.D{}) -	if err != nil { -		log.Fatal(err) -	} -	defer cur.Close(context.Background()) - -	for cur.Next(context.Background()) { -		var result U2FDeviceHandleV3 -		err := cur.Decode(&result) -		if err != nil { -			log.Fatal(err) -		} - -		kH, err := decodeWebsafeBase64(result.Registration.KeyHandle) - -		if err != nil { -			log.Fatal(err) -		} - -		pK, err := decodeWebsafeBase64(result.Registration.PublicKey) - -		if err != nil { -			log.Fatal(err) -		} - -		err = dbProvider.SaveU2FDeviceHandle(result.UserID, kH, pK) - -		if err != nil { -			log.Fatal(err) -		} -	} -	if err := cur.Err(); err != nil { -		log.Fatal(err) -	} -} - -func migrateMongoTOTPDevices(db *mongo.Database, dbProvider storage.Provider) { -	u2fCollection := db.Collection("totp_secrets") - -	cur, err := u2fCollection.Find(context.Background(), bson.D{}) -	if err != nil { -		log.Fatal(err) -	} -	defer cur.Close(context.Background()) - -	for cur.Next(context.Background()) { -		var result TOTPSecretsV3 -		err := cur.Decode(&result) -		if err != nil { -			log.Fatal(err) -		} - -		err = dbProvider.SaveTOTPSecret(result.UserID, result.Secret.Base32) - -		if err != nil { -			log.Fatal(err) -		} -	} -	if err := cur.Err(); err != nil { -		log.Fatal(err) -	} -} - -func migrateMongoPreferences(db *mongo.Database, dbProvider storage.Provider) { -	u2fCollection := db.Collection("prefered_2fa_method") //nolint:misspell - -	cur, err := u2fCollection.Find(context.Background(), bson.D{}) -	if err != nil { -		log.Fatal(err) -	} -	defer cur.Close(context.Background()) - -	for cur.Next(context.Background()) { -		var result PreferencesV3 -		err := cur.Decode(&result) -		if err != nil { -			log.Fatal(err) -		} - -		err = dbProvider.SavePreferred2FAMethod(result.UserID, result.Method) - -		if err != nil { -			log.Fatal(err) -		} -	} -	if err := cur.Err(); err != nil { -		log.Fatal(err) -	} -} - -func migrateMongoAuthenticationTraces(db *mongo.Database, dbProvider storage.Provider) { -	u2fCollection := db.Collection("authentication_traces") - -	cur, err := u2fCollection.Find(context.Background(), bson.D{}) -	if err != nil { -		log.Fatal(err) -	} -	defer cur.Close(context.Background()) - -	for cur.Next(context.Background()) { -		var result AuthenticationTraceV3 -		err := cur.Decode(&result) -		if err != nil { -			log.Fatal(err) -		} - -		attempt := models.AuthenticationAttempt{ -			Username:   result.UserID, -			Successful: result.Successful, -			Time:       time.Unix(result.Date.Date/1000.0, 0), -		} - -		err = dbProvider.AppendAuthenticationLog(attempt) - -		if err != nil { -			log.Fatal(err) -		} -	} -	if err := cur.Err(); err != nil { -		log.Fatal(err) -	} -}  | 
