Skip to content

Commit 256fdab

Browse files
committed
feat: enhance authorization configuration with new signature algorithms and backward compatibility
1 parent 0f4bb1a commit 256fdab

1 file changed

Lines changed: 88 additions & 62 deletions

File tree

pkg/identity/identity.go

Lines changed: 88 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,33 @@ type Store interface {
5656
DecryptMessage(cipher []byte, peerID string) ([]byte, error)
5757
}
5858

59+
// SignatureAlgorithm represents supported signature algorithms
60+
type SignatureAlgorithm string
61+
62+
const (
63+
AlgorithmEd25519 SignatureAlgorithm = "ed25519"
64+
AlgorithmP256 SignatureAlgorithm = "p256"
65+
)
66+
5967
// AuthorizerInfo represents a single authorizer with their public key and algorithm
6068
type AuthorizerInfo struct {
61-
PublicKey string `json:"public_key"`
62-
Algorithm string `json:"algorithm"` // "ed25519" or "secp256k1"
69+
PublicKey string `json:"public_key"`
70+
Algorithm SignatureAlgorithm `json:"algorithm"`
6371
}
6472

6573
// AuthorizationConfig holds the cached authorization configuration
6674
type AuthorizationConfig struct {
67-
Enabled bool
68-
RequiredAuthorizers int
69-
AuthorizerPublicKeys map[string]AuthorizerInfo // key is authorizer ID
75+
Enabled bool `mapstructure:"enabled"`
76+
RequiredAuthorizers int `mapstructure:"required_authorizers"`
77+
AuthorizerPublicKeys map[string]AuthorizerInfo `mapstructure:"authorizer_public_keys"`
78+
Authorizers map[string]AuthorizerInfo `mapstructure:"authorizers"` // backward compatibility
79+
}
80+
81+
// AuthorizerConfigEntry represents the raw configuration for an authorizer
82+
type AuthorizerConfigEntry struct {
83+
PublicKey string `mapstructure:"public_key"`
84+
Algorithm string `mapstructure:"algorithm"`
85+
Pubkey string `mapstructure:"pubkey"` // backward compatibility
7086
}
7187

7288
// fileStore implements the Store interface using the filesystem
@@ -170,70 +186,87 @@ func NewFileStore(identityDir, nodeName string, decrypt bool) (*fileStore, error
170186
}
171187

172188
// Load authorization configuration
173-
store.authzConfig = AuthorizationConfig{
189+
if err := store.loadAuthorizationConfig(); err != nil {
190+
return nil, fmt.Errorf("failed to load authorization config: %w", err)
191+
}
192+
193+
return store, nil
194+
}
195+
196+
// loadAuthorizationConfig loads and caches the authorization configuration
197+
func (s *fileStore) loadAuthorizationConfig() error {
198+
// Load base configuration
199+
s.authzConfig = AuthorizationConfig{
174200
Enabled: viper.GetBool("authorization.enabled"),
175201
RequiredAuthorizers: viper.GetInt("authorization.required_authorizers"),
176202
AuthorizerPublicKeys: make(map[string]AuthorizerInfo),
203+
Authorizers: make(map[string]AuthorizerInfo),
177204
}
178205

179-
// Load authorizer public keys
180-
authKeys := viper.GetStringMap("authorization.authorizer_public_keys")
181-
for authID, authData := range authKeys {
182-
if authInfo, ok := authData.(map[string]interface{}); ok {
183-
info := AuthorizerInfo{
184-
Algorithm: "ed25519", // default algorithm
185-
}
186-
187-
if pubKey, ok := authInfo["public_key"].(string); ok && pubKey != "" {
188-
info.PublicKey = pubKey
189-
}
190-
191-
if algo, ok := authInfo["algorithm"].(string); ok && algo != "" {
192-
info.Algorithm = algo
193-
}
194-
195-
if info.PublicKey != "" {
196-
store.authzConfig.AuthorizerPublicKeys[authID] = info
197-
store.authorizerInfo[authID] = info
198-
}
206+
// Load authorizer public keys (new format)
207+
authKeysConfig := viper.GetStringMap("authorization.authorizer_public_keys")
208+
for authID, authData := range authKeysConfig {
209+
info, err := parseAuthorizerConfig(authData, true)
210+
if err != nil {
211+
logger.Warn("Failed to parse authorizer config", "authorizerID", authID, "error", err)
212+
continue
213+
}
214+
if info.PublicKey != "" {
215+
s.authzConfig.AuthorizerPublicKeys[authID] = info
216+
s.authorizerInfo[authID] = info
199217
}
200218
}
201219

202220
// Load global authorizer configuration (backward compatibility)
203-
authzAuthorizers := viper.GetStringMap("authorization.authorizers")
204-
for id, v := range authzAuthorizers {
205-
// Skip if already loaded from operation-specific config
206-
if _, exists := store.authorizerInfo[id]; exists {
221+
authorizersConfig := viper.GetStringMap("authorization.authorizers")
222+
for authID, authData := range authorizersConfig {
223+
// Skip if already loaded from new format
224+
if _, exists := s.authorizerInfo[authID]; exists {
207225
continue
208226
}
209227

210-
// v is expected to be a map with key "pubkey" and optional "algorithm"
211-
if entry, ok := v.(map[string]interface{}); ok {
212-
info := AuthorizerInfo{
213-
Algorithm: "ed25519", // default algorithm
214-
}
228+
info, err := parseAuthorizerConfig(authData, false)
229+
if err != nil {
230+
logger.Warn("Failed to parse legacy authorizer config", "authorizerID", authID, "error", err)
231+
continue
232+
}
233+
if info.PublicKey != "" {
234+
s.authzConfig.Authorizers[authID] = info
235+
s.authorizerInfo[authID] = info
236+
}
237+
}
215238

216-
if pubHexRaw, ok := entry["pubkey"]; ok {
217-
if pubHex, ok := pubHexRaw.(string); ok && pubHex != "" {
218-
info.PublicKey = pubHex
219-
}
220-
}
239+
return nil
240+
}
221241

222-
if algoRaw, ok := entry["algorithm"]; ok {
223-
if algo, ok := algoRaw.(string); ok && algo != "" {
224-
info.Algorithm = algo
225-
}
226-
}
242+
// parseAuthorizerConfig parses authorizer configuration from interface{} to AuthorizerInfo
243+
func parseAuthorizerConfig(authData interface{}, isNewFormat bool) (AuthorizerInfo, error) {
244+
info := AuthorizerInfo{
245+
Algorithm: AlgorithmEd25519, // default algorithm
246+
}
227247

228-
if info.PublicKey != "" {
229-
store.authorizerInfo[id] = info
230-
} else {
231-
logger.Warn("Invalid or empty pubkey for authorizer", "authorizerID", id)
232-
}
248+
authMap, ok := authData.(map[string]interface{})
249+
if !ok {
250+
return info, fmt.Errorf("invalid authorizer config format")
251+
}
252+
253+
// Parse public key (handle both new and legacy formats)
254+
if isNewFormat {
255+
if pubKey, ok := authMap["public_key"].(string); ok && pubKey != "" {
256+
info.PublicKey = pubKey
257+
}
258+
} else {
259+
if pubKey, ok := authMap["pubkey"].(string); ok && pubKey != "" {
260+
info.PublicKey = pubKey
233261
}
234262
}
235263

236-
return store, nil
264+
// Parse algorithm
265+
if algo, ok := authMap["algorithm"].(string); ok && algo != "" {
266+
info.Algorithm = SignatureAlgorithm(algo)
267+
}
268+
269+
return info, nil
237270
}
238271

239272
// loadPrivateKey loads the private key from file, decrypting if necessary
@@ -551,9 +584,9 @@ func (s *fileStore) AuthorizeInitiatorMessage(operation string, msg types.Initia
551584
}
552585

553586
// verifySignatureByAlgorithm verifies a signature using the specified algorithm
554-
func verifySignatureByAlgorithm(publicKeyHex, algorithm string, message, signature []byte) (bool, error) {
587+
func verifySignatureByAlgorithm(publicKeyHex string, algorithm SignatureAlgorithm, message, signature []byte) (bool, error) {
555588
switch algorithm {
556-
case "ed25519":
589+
case AlgorithmEd25519:
557590
pubKeyBytes, err := hex.DecodeString(publicKeyHex)
558591
if err != nil {
559592
return false, fmt.Errorf("invalid ed25519 public key hex: %w", err)
@@ -563,21 +596,14 @@ func verifySignatureByAlgorithm(publicKeyHex, algorithm string, message, signatu
563596
}
564597
return ed25519.Verify(pubKeyBytes, message, signature), nil
565598

566-
case "secp256k1", "p256":
599+
case AlgorithmP256:
567600
pubKeyBytes, err := hex.DecodeString(publicKeyHex)
568601
if err != nil {
569602
return false, fmt.Errorf("invalid ecdsa public key hex: %w", err)
570603
}
571604

572605
// Parse the public key
573-
var curve elliptic.Curve
574-
if algorithm == "secp256k1" {
575-
// For secp256k1, we'd need to import a secp256k1 library
576-
// For now, we'll use P256 as a placeholder
577-
curve = elliptic.P256()
578-
} else {
579-
curve = elliptic.P256()
580-
}
606+
curve := elliptic.P256()
581607

582608
// Assume uncompressed point format (0x04 + 32 bytes x + 32 bytes y)
583609
if len(pubKeyBytes) == 65 && pubKeyBytes[0] == 0x04 {

0 commit comments

Comments
 (0)