github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cmd/oauth2-server/main.go (about)

     1  // Copyright 2024 PingCAP, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package main
    15  
    16  import (
    17  	"fmt"
    18  	"net/http"
    19  
    20  	"github.com/go-oauth2/oauth2/v4/errors"
    21  	"github.com/go-oauth2/oauth2/v4/generates"
    22  	"github.com/go-oauth2/oauth2/v4/manage"
    23  	"github.com/go-oauth2/oauth2/v4/models"
    24  	"github.com/go-oauth2/oauth2/v4/server"
    25  	"github.com/go-oauth2/oauth2/v4/store"
    26  	"github.com/golang-jwt/jwt"
    27  	"github.com/pingcap/log"
    28  	"github.com/spf13/cobra"
    29  	"go.uber.org/zap"
    30  )
    31  
    32  const openIDConfiguration = `
    33  {
    34    "issuer": "http://localhost:%d/",
    35    "authorization_endpoint": "http://localhost:%d/authorize",
    36    "token_endpoint": "http://localhost:%d/token",
    37    "scopes_supported": [
    38      "openid",
    39      "profile"
    40    ],
    41    "response_types_supported": [
    42      "code",
    43      "token",
    44      "id_token",
    45      "code token",
    46      "code id_token",
    47      "token id_token",
    48      "code token id_token"
    49    ],
    50    "code_challenge_methods_supported": [
    51      "HS256",
    52      "plain"
    53    ],
    54    "response_modes_supported": [
    55      "query",
    56      "fragment",
    57      "form_post"
    58    ],
    59    "subject_types_supported": [
    60      "public"
    61    ],
    62    "id_token_signing_alg_values_supported": [
    63      "HS256"
    64    ],
    65    "token_endpoint_auth_methods_supported": [
    66      "client_secret_basic",
    67      "client_secret_post",
    68      "private_key_jwt"
    69    ],
    70    "claims_supported": [
    71      "aud",
    72      "created_at",
    73      "email",
    74      "email_verified",
    75      "exp",
    76      "iat",
    77      "identities",
    78      "iss",
    79      "name"
    80    ],
    81    "request_uri_parameter_supported": false,
    82    "request_parameter_supported": false
    83  }
    84  `
    85  
    86  type oauth2ServerConfig struct {
    87  	tokenSignSecret string
    88  	clientID        string
    89  	clientSecret    string
    90  	port            int
    91  }
    92  
    93  var serverConfig = newServerConfig()
    94  
    95  func newServerConfig() *oauth2ServerConfig {
    96  	return &oauth2ServerConfig{}
    97  }
    98  
    99  func main() {
   100  	cmd := &cobra.Command{
   101  		Use: "oauth2 server",
   102  		Run: run,
   103  	}
   104  	// Flags for the root command
   105  	cmd.Flags().StringVar(&serverConfig.tokenSignSecret, "token-secret",
   106  		"SJhX36_KapYSybBtJq35lxX_Brr4LRURSkm7QmXJGmy8pUFW9EIOcVQPsykz9-jj", "Secret to sign token")
   107  	cmd.Flags().StringVar(&serverConfig.clientID, "client-id", "1234", "Client ID of oauth2")
   108  	cmd.Flags().StringVar(&serverConfig.clientSecret, "client-secret", "e0KVlA2EiBfjoN13olyZd2kv1KL", "Client secret of oauth2")
   109  	cmd.Flags().IntVar(&serverConfig.port, "log-file", 9096, "log file path")
   110  	if err := cmd.Execute(); err != nil {
   111  		fmt.Println(err)
   112  	}
   113  }
   114  
   115  func run(_ *cobra.Command, _ []string) {
   116  	manager := manage.NewDefaultManager()
   117  	// token memory store
   118  	manager.MustTokenStorage(store.NewMemoryTokenStore())
   119  	manager.MapAccessGenerate(generates.NewJWTAccessGenerate("", []byte(serverConfig.tokenSignSecret), jwt.SigningMethodHS512))
   120  
   121  	// client memory store
   122  	clientStore := store.NewClientStore()
   123  	err := clientStore.Set(serverConfig.clientID, &models.Client{
   124  		ID:     serverConfig.clientID,
   125  		Secret: serverConfig.clientSecret,
   126  		Domain: fmt.Sprintf("http://localhost:%d", serverConfig.port),
   127  	})
   128  	if err != nil {
   129  		log.Panic("set client failed", zap.Error(err))
   130  	}
   131  	manager.MapClientStorage(clientStore)
   132  
   133  	srv := server.NewDefaultServer(manager)
   134  	srv.SetAllowGetAccessRequest(true)
   135  	srv.SetClientInfoHandler(server.ClientFormHandler)
   136  	srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
   137  		log.Error("Internal Error:", zap.Error(err))
   138  		return
   139  	})
   140  	srv.SetResponseErrorHandler(func(re *errors.Response) {
   141  		log.Error("Response Error:", zap.Error(re.Error))
   142  	})
   143  	http.Handle("/authorize", logMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   144  		err := srv.HandleAuthorizeRequest(w, r)
   145  		if err != nil {
   146  			http.Error(w, err.Error(), http.StatusBadRequest)
   147  		}
   148  	})))
   149  	http.Handle("/token", logMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   150  		if err := srv.HandleTokenRequest(w, r); err != nil {
   151  			http.Error(w, err.Error(), http.StatusInternalServerError)
   152  		}
   153  	})))
   154  	http.Handle("/.well-known/openid-configuration", logMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   155  		_, _ = w.Write([]byte(fmt.Sprintf(openIDConfiguration, serverConfig.port, serverConfig.port, serverConfig.port)))
   156  		w.WriteHeader(200)
   157  	})))
   158  	log.Info("starting auth2 server", zap.Int("port", serverConfig.port))
   159  	log.Panic("run auth2 server failed", zap.Error(http.ListenAndServe(fmt.Sprintf(":%d", serverConfig.port), nil)))
   160  }
   161  
   162  func logMiddleware(next http.Handler) http.Handler {
   163  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   164  		next.ServeHTTP(w, r)
   165  		log.Info("oauth server api is called", zap.String("path", r.URL.Path))
   166  	})
   167  }