forked from casdoor/casdoor
feat: use org name as TOTP issuer (#4731)
This commit is contained in:
@@ -64,7 +64,14 @@ func (c *ApiController) MfaSetupInitiate() {
|
||||
return
|
||||
}
|
||||
|
||||
mfaProps, err := MfaUtil.Initiate(user.GetId())
|
||||
issuer := ""
|
||||
if organization != nil && organization.DisplayName != "" {
|
||||
issuer = organization.DisplayName
|
||||
} else if organization != nil {
|
||||
issuer = organization.Name
|
||||
}
|
||||
|
||||
mfaProps, err := MfaUtil.Initiate(user.GetId(), issuer)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
||||
@@ -32,7 +32,7 @@ type MfaProps struct {
|
||||
}
|
||||
|
||||
type MfaInterface interface {
|
||||
Initiate(userId string) (*MfaProps, error)
|
||||
Initiate(userId string, issuer string) (*MfaProps, error)
|
||||
SetupVerify(passcode string) error
|
||||
Enable(user *User) error
|
||||
Verify(passcode string) error
|
||||
|
||||
@@ -31,7 +31,7 @@ type PushMfa struct {
|
||||
challengeExp time.Time
|
||||
}
|
||||
|
||||
func (mfa *PushMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
func (mfa *PushMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ type RadiusMfa struct {
|
||||
provider *Provider
|
||||
}
|
||||
|
||||
func (mfa *RadiusMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
func (mfa *RadiusMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestRadiusMfaUtil(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test Initiate
|
||||
mfaProps, err := radiusMfa.Initiate("test/user")
|
||||
mfaProps, err := radiusMfa.Initiate("test/user", "")
|
||||
if err != nil {
|
||||
t.Errorf("Initiate failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type SmsMfa struct {
|
||||
*MfaProps
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
func (mfa *SmsMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
|
||||
@@ -33,12 +33,11 @@ type TotpMfa struct {
|
||||
digits otp.Digits
|
||||
}
|
||||
|
||||
func (mfa *TotpMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
//issuer := beego.AppConfig.String("appname")
|
||||
//if issuer == "" {
|
||||
// issuer = "casdoor"
|
||||
//}
|
||||
issuer := "Casdoor"
|
||||
func (mfa *TotpMfa) Initiate(userId string, issuer string) (*MfaProps, error) {
|
||||
// Use the provided issuer (application display name), or fall back to "Casdoor" if not provided
|
||||
if issuer == "" {
|
||||
issuer = "Casdoor"
|
||||
}
|
||||
|
||||
key, err := totp.Generate(totp.GenerateOpts{
|
||||
Issuer: issuer,
|
||||
|
||||
115
object/mfa_totp_test.go
Normal file
115
object/mfa_totp_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2025 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTotpMfaUtil(t *testing.T) {
|
||||
// Test creating a new TOTP MFA util
|
||||
config := &MfaProps{
|
||||
MfaType: TotpType,
|
||||
}
|
||||
|
||||
totpMfa := NewTotpMfaUtil(config)
|
||||
if totpMfa == nil {
|
||||
t.Error("NewTotpMfaUtil returned nil")
|
||||
return
|
||||
}
|
||||
|
||||
if totpMfa.MfaType != TotpType {
|
||||
t.Errorf("Expected MFA type %s, got %s", TotpType, totpMfa.MfaType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotpMfaInitiate_WithCustomIssuer(t *testing.T) {
|
||||
totpMfa := NewTotpMfaUtil(nil)
|
||||
// Test with custom issuer (application display name)
|
||||
customIssuer := "My Application"
|
||||
mfaProps, err := totpMfa.Initiate("test/user", customIssuer)
|
||||
if err != nil {
|
||||
t.Errorf("Initiate failed: %v", err)
|
||||
}
|
||||
|
||||
if mfaProps == nil {
|
||||
t.Error("Initiate returned nil mfaProps")
|
||||
return
|
||||
}
|
||||
|
||||
if mfaProps.MfaType != TotpType {
|
||||
t.Errorf("Expected MFA type %s, got %s", TotpType, mfaProps.MfaType)
|
||||
}
|
||||
|
||||
if mfaProps.Secret == "" {
|
||||
t.Error("Secret should not be empty")
|
||||
}
|
||||
|
||||
if mfaProps.URL == "" {
|
||||
t.Error("URL should not be empty")
|
||||
}
|
||||
|
||||
// Verify the URL contains the custom issuer (URL-encoded or plain)
|
||||
if !strings.Contains(mfaProps.URL, customIssuer) && !strings.Contains(mfaProps.URL, "My%20Application") {
|
||||
t.Errorf("URL should contain custom issuer '%s', got: %s", customIssuer, mfaProps.URL)
|
||||
}
|
||||
|
||||
// Verify the URL contains the user ID
|
||||
if !strings.Contains(mfaProps.URL, "test/user") {
|
||||
t.Errorf("URL should contain user ID 'test/user', got: %s", mfaProps.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotpMfaInitiate_WithEmptyIssuer(t *testing.T) {
|
||||
totpMfa := NewTotpMfaUtil(nil)
|
||||
// Test with empty issuer (should default to "Casdoor")
|
||||
mfaProps, err := totpMfa.Initiate("test/user", "")
|
||||
if err != nil {
|
||||
t.Errorf("Initiate failed: %v", err)
|
||||
}
|
||||
|
||||
if mfaProps == nil {
|
||||
t.Error("Initiate returned nil mfaProps")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the URL contains the default issuer "Casdoor"
|
||||
if !strings.Contains(mfaProps.URL, "Casdoor") {
|
||||
t.Errorf("URL should contain default issuer 'Casdoor', got: %s", mfaProps.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMfaUtil_Totp(t *testing.T) {
|
||||
config := &MfaProps{
|
||||
MfaType: TotpType,
|
||||
Secret: "testsecret",
|
||||
}
|
||||
|
||||
mfaUtil := GetMfaUtil(TotpType, config)
|
||||
if mfaUtil == nil {
|
||||
t.Error("GetMfaUtil returned nil for TOTP type")
|
||||
return
|
||||
}
|
||||
|
||||
totpMfa, ok := mfaUtil.(*TotpMfa)
|
||||
if !ok {
|
||||
t.Error("GetMfaUtil did not return TotpMfa type")
|
||||
}
|
||||
|
||||
if totpMfa.MfaType != TotpType {
|
||||
t.Errorf("Expected MFA type %s, got %s", TotpType, totpMfa.MfaType)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user