pkg/authority/v1alpha1/tools.go (104 lines of code) (raw):

// 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 v1alpha1 import ( "context" "encoding/json" "fmt" "net" "strings" "github.com/apache/dubbo-admin/pkg/authority/jwt" "google.golang.org/grpc/credentials" "github.com/apache/dubbo-admin/pkg/authority/cert" "github.com/apache/dubbo-admin/pkg/authority/config" "github.com/apache/dubbo-admin/pkg/authority/k8s" "github.com/apache/dubbo-admin/pkg/authority/rule" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" ) func ExactEndpoint(c context.Context, certStorage cert.Storage, options *config.Options, kubeClient k8s.Client) (*rule.Endpoint, error) { if c == nil { return nil, fmt.Errorf("context is nil") } p, ok := peer.FromContext(c) if !ok { return nil, fmt.Errorf("failed to get peer from context") } endpoint, endpointErr := tryFromHeader(c, certStorage, options, kubeClient) if endpointErr == nil { return endpoint, nil } endpoint, connectionErr := tryFromConnection(p) if connectionErr == nil { return endpoint, nil } if !options.IsTrustAnyone && connectionErr != nil { return nil, fmt.Errorf("Failed to get endpoint from header: %s. Failed to get endpoint from connection: %s. RemoteAddr: %s", endpointErr.Error(), connectionErr.Error(), p.Addr.String()) } host, _, err := net.SplitHostPort(p.Addr.String()) if err != nil { return nil, err } return &rule.Endpoint{ ID: p.Addr.String(), Ips: []string{host}, }, nil } func tryFromHeader(c context.Context, certStorage cert.Storage, options *config.Options, kubeClient k8s.Client) (*rule.Endpoint, error) { // TODO refactor as coreos/go-oidc authorization := metadata.ValueFromIncomingContext(c, "authorization") if len(authorization) != 1 { return nil, fmt.Errorf("failed to get Authorization header from context") } if !strings.HasPrefix(authorization[0], "Bearer ") { return nil, fmt.Errorf("failed to get Authorization header from context") } token := strings.ReplaceAll(authorization[0], "Bearer ", "") authorizationTypes := metadata.ValueFromIncomingContext(c, "authorization-type") authorizationType := "kubernetes" if len(authorizationTypes) == 1 { authorizationType = authorizationTypes[0] } if authorizationType == "dubbo-jwt" { for _, c := range certStorage.GetTrustedCerts() { claims, err := jwt.Verify(&c.PrivateKey.PublicKey, token) if err != nil { continue } endpoint := &rule.Endpoint{SpiffeID: claims.Subject} err = json.Unmarshal([]byte(claims.Extensions), endpoint) if err != nil { continue } return endpoint, nil } return nil, fmt.Errorf("failed to verify Authorization header from dubbo-jwt") } if options.IsKubernetesConnected && options.EnableOIDCCheck { endpoint, ok := kubeClient.VerifyServiceAccount(token, authorizationType) if !ok { return nil, fmt.Errorf("failed to verify Authorization header from kubernetes") } return endpoint, nil } return nil, fmt.Errorf("failed to verify Authorization header") } func tryFromConnection(p *peer.Peer) (*rule.Endpoint, error) { if p.AuthInfo != nil && p.AuthInfo.AuthType() == "tls" { tlsInfo, ok := p.AuthInfo.(credentials.TLSInfo) if !ok { return nil, fmt.Errorf("failed to get TLSInfo from peer") } host, _, err := net.SplitHostPort(p.Addr.String()) if err != nil { return nil, err } if tlsInfo.SPIFFEID == nil { return nil, fmt.Errorf("failed to get SPIFFE ID from peer") } return &rule.Endpoint{ ID: p.Addr.String(), SpiffeID: tlsInfo.SPIFFEID.String(), Ips: []string{host}, }, nil } return nil, fmt.Errorf("failed to get TLSInfo from peer") }