...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/auth/gcp/service.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/auth/gcp

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package gcp
    17  
    18  import (
    19  	"net/http"
    20  	"net/url"
    21  	"path"
    22  
    23  	"github.com/gin-gonic/gin"
    24  	"github.com/go-logr/logr"
    25  	"golang.org/x/oauth2"
    26  	"golang.org/x/oauth2/google"
    27  
    28  	config "github.com/chaos-mesh/chaos-mesh/pkg/config"
    29  	"github.com/chaos-mesh/chaos-mesh/pkg/dashboard/apiserver/utils"
    30  )
    31  
    32  type Service struct {
    33  	clientId     string
    34  	clientSecret string
    35  	rootUrl      *url.URL
    36  	logger       logr.Logger
    37  }
    38  
    39  // NewService returns an experiment service instance.
    40  func NewService(
    41  	conf *config.ChaosDashboardConfig,
    42  	logger logr.Logger,
    43  ) (*Service, error) {
    44  	rootUrl, err := url.Parse(conf.RootUrl)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	if rootUrl.Path == "" {
    49  		rootUrl.Path = "/"
    50  	}
    51  
    52  	return &Service{
    53  		clientId:     conf.GcpClientId,
    54  		clientSecret: conf.GcpClientSecret,
    55  		rootUrl:      rootUrl,
    56  		logger:       logger.WithName("gcp auth api"),
    57  	}, nil
    58  }
    59  
    60  // Register mounts HTTP handler on the mux.
    61  func Register(r *gin.RouterGroup, s *Service, conf *config.ChaosDashboardConfig) {
    62  	// If the gcp security mode is not set, just skip the registration
    63  	if !conf.GcpSecurityMode {
    64  		return
    65  	}
    66  
    67  	r.Use(s.Middleware)
    68  
    69  	endpoint := r.Group("/auth/gcp")
    70  	endpoint.GET("/redirect", s.handleRedirect)
    71  	endpoint.GET("/callback", s.authCallback)
    72  }
    73  
    74  func (s *Service) getOauthConfig(c *gin.Context) oauth2.Config {
    75  	url := *s.rootUrl
    76  	url.Path = path.Join(s.rootUrl.Path, "./api/auth/gcp/callback")
    77  
    78  	return oauth2.Config{
    79  		ClientID:     s.clientId,
    80  		ClientSecret: s.clientSecret,
    81  		RedirectURL:  url.String(),
    82  		Scopes: []string{
    83  			"email", "profile",
    84  			"https://www.googleapis.com/auth/userinfo.email",
    85  			"https://www.googleapis.com/auth/compute",
    86  			"https://www.googleapis.com/auth/cloud-platform",
    87  		},
    88  		Endpoint: google.Endpoint,
    89  	}
    90  }
    91  
    92  func (s *Service) handleRedirect(c *gin.Context) {
    93  	oauth := s.getOauthConfig(c)
    94  	uri := oauth.AuthCodeURL("", oauth2.AccessTypeOffline, oauth2.ApprovalForce)
    95  
    96  	c.Redirect(http.StatusFound, uri)
    97  }
    98  
    99  func (s *Service) authCallback(c *gin.Context) {
   100  	ctx := c.Request.Context()
   101  
   102  	oauth := s.getOauthConfig(c)
   103  	oauth2Token, err := oauth.Exchange(ctx, c.Request.URL.Query().Get("code"), oauth2.AccessTypeOffline, oauth2.ApprovalForce)
   104  	if err != nil {
   105  		utils.SetAPIError(c, utils.ErrInternalServer.WrapWithNoMessage(err))
   106  		return
   107  	}
   108  
   109  	setCookie(c, oauth2Token)
   110  	target := url.URL{
   111  		Path: "/",
   112  	}
   113  	c.Redirect(http.StatusFound, target.RequestURI())
   114  }
   115