blob: 3625a08b6a6c9791ac1a701f978bbbc385861b7f [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 bufconnect
import (
"errors"
"fmt"
"strings"
)
import (
"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/app"
)
// NewTokenProviderFromContainer creates a singleTokenProvider from the BUF_TOKEN environment variable
func NewTokenProviderFromContainer(container app.EnvContainer) (TokenProvider, error) {
return newTokenProviderFromString(container.Env(tokenEnvKey), true)
}
// NewTokenProviderFromString creates a singleTokenProvider by the token provided
func NewTokenProviderFromString(token string) (TokenProvider, error) {
return newTokenProviderFromString(token, false)
}
// newTokenProviderFromString returns a TokenProvider with auth keys from the provided token. The
// remote token is in the format: token1@remote1,token2@remote2.
// The special characters `@` and `,` are used as the splitters. The tokens and remote addresses
// do not contain these characters since they are enforced by the rules in BSR.
func newTokenProviderFromString(token string, isFromEnvVar bool) (TokenProvider, error) {
if token == "" {
return nopTokenProvider{}, nil
}
// Tokens for different remotes are separated by `,`. Using strings.Split to separate the string into remote tokens.
tokens := strings.Split(token, ",")
if len(tokens) == 1 {
if strings.Contains(tokens[0], "@") {
return newMultipleTokenProvider(tokens, isFromEnvVar)
}
return newSingleTokenProvider(tokens[0], isFromEnvVar)
}
return newMultipleTokenProvider(tokens, isFromEnvVar)
}
// singleTokenProvider is used to provide set of authentication tokenToAuthKey.
type singleTokenProvider struct {
// true: the tokenSet is generated from environment variable tokenEnvKey
// false: otherwise
setBufTokenEnvVar bool
token string
}
func newSingleTokenProvider(token string, isFromEnvVar bool) (*singleTokenProvider, error) {
if strings.Contains(token, "@") {
return nil, errors.New("token cannot contain special character `@`")
}
if strings.Contains(token, ",") {
return nil, errors.New("token cannot contain special character `,`")
}
if token == "" {
return nil, errors.New("single token cannot be empty")
}
return &singleTokenProvider{
setBufTokenEnvVar: isFromEnvVar,
token: token,
}, nil
}
// RemoteToken finds the token by the remote address
func (t *singleTokenProvider) RemoteToken(address string) string {
return t.token
}
func (t *singleTokenProvider) IsFromEnvVar() bool {
return t.setBufTokenEnvVar
}
type multipleTokenProvider struct {
addressToToken map[string]string
isFromEnvVar bool
}
func newMultipleTokenProvider(tokens []string, isFromEnvVar bool) (*multipleTokenProvider, error) {
addressToToken := make(map[string]string)
for _, token := range tokens {
split := strings.Split(token, "@")
if len(split) != 2 {
return nil, fmt.Errorf("invalid token: %s", token)
}
if split[0] == "" || split[1] == "" {
return nil, fmt.Errorf("invalid token: %s", token)
}
if strings.Contains(split[0], ":") {
return nil, fmt.Errorf("invalid token: %s, token cannot contain special character `:`", token)
}
if strings.Contains(split[0], ",") {
return nil, fmt.Errorf("invalid token: %s, token cannot contain special character `,`", token)
}
if _, ok := addressToToken[split[1]]; ok {
return nil, fmt.Errorf("invalid token: %s, repeated remote adddress: %s", token, split[1])
}
addressToToken[split[1]] = split[0]
}
return &multipleTokenProvider{
addressToToken: addressToToken,
isFromEnvVar: isFromEnvVar,
}, nil
}
func (m *multipleTokenProvider) RemoteToken(address string) string {
return m.addressToToken[address]
}
func (m *multipleTokenProvider) IsFromEnvVar() bool {
return m.isFromEnvVar
}
type nopTokenProvider struct{}
func (nopTokenProvider) RemoteToken(string) string {
return ""
}
func (nopTokenProvider) IsFromEnvVar() bool {
return false
}