gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

idp.go (3669B)


      1 // GoToSocial
      2 // Copyright (C) GoToSocial Authors admin@gotosocial.org
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 //
      5 // This program is free software: you can redistribute it and/or modify
      6 // it under the terms of the GNU Affero General Public License as published by
      7 // the Free Software Foundation, either version 3 of the License, or
      8 // (at your option) any later version.
      9 //
     10 // This program is distributed in the hope that it will be useful,
     11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 // GNU Affero General Public License for more details.
     14 //
     15 // You should have received a copy of the GNU Affero General Public License
     16 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 package oidc
     19 
     20 import (
     21 	"context"
     22 	"fmt"
     23 
     24 	"github.com/coreos/go-oidc/v3/oidc"
     25 	"github.com/superseriousbusiness/gotosocial/internal/config"
     26 	"github.com/superseriousbusiness/gotosocial/internal/gtserror"
     27 	"golang.org/x/oauth2"
     28 )
     29 
     30 const (
     31 	// CallbackPath is the API path for receiving callback tokens from external OIDC providers
     32 	CallbackPath = "/auth/callback"
     33 )
     34 
     35 // IDP contains logic for parsing an OIDC access code into a set of claims by calling an external OIDC provider.
     36 type IDP interface {
     37 	// HandleCallback accepts a context (pass the context from the http.Request), and an oauth2 code as returned from a successful
     38 	// login through an OIDC provider. It uses the code to request a token from the OIDC provider, which should contain an id_token
     39 	// with a set of claims.
     40 	//
     41 	// Note that this function *does not* verify state. That should be handled by the caller *before* this function is called.
     42 	HandleCallback(ctx context.Context, code string) (*Claims, gtserror.WithCode)
     43 	// AuthCodeURL returns the proper redirect URL for this IDP, for redirecting requesters to the correct OIDC endpoint.
     44 	AuthCodeURL(state string) string
     45 }
     46 
     47 type idp struct {
     48 	oauth2Config oauth2.Config
     49 	provider     *oidc.Provider
     50 	oidcConf     *oidc.Config
     51 }
     52 
     53 // NewIDP returns a new IDP configured with the given config.
     54 func NewIDP(ctx context.Context) (IDP, error) {
     55 	// validate config fields
     56 	idpName := config.GetOIDCIdpName()
     57 	if idpName == "" {
     58 		return nil, fmt.Errorf("not set: IDPName")
     59 	}
     60 
     61 	issuer := config.GetOIDCIssuer()
     62 	if issuer == "" {
     63 		return nil, fmt.Errorf("not set: Issuer")
     64 	}
     65 
     66 	clientID := config.GetOIDCClientID()
     67 	if clientID == "" {
     68 		return nil, fmt.Errorf("not set: ClientID")
     69 	}
     70 
     71 	clientSecret := config.GetOIDCClientSecret()
     72 	if clientSecret == "" {
     73 		return nil, fmt.Errorf("not set: ClientSecret")
     74 	}
     75 
     76 	scopes := config.GetOIDCScopes()
     77 	if len(scopes) == 0 {
     78 		return nil, fmt.Errorf("not set: Scopes")
     79 	}
     80 
     81 	provider, err := oidc.NewProvider(ctx, issuer)
     82 	if err != nil {
     83 		return nil, err
     84 	}
     85 
     86 	protocol := config.GetProtocol()
     87 	host := config.GetHost()
     88 
     89 	oauth2Config := oauth2.Config{
     90 		// client_id and client_secret of the client.
     91 		ClientID:     clientID,
     92 		ClientSecret: clientSecret,
     93 
     94 		// The redirectURL.
     95 		RedirectURL: fmt.Sprintf("%s://%s%s", protocol, host, CallbackPath),
     96 
     97 		// Discovery returns the OAuth2 endpoints.
     98 		Endpoint: provider.Endpoint(),
     99 
    100 		// "openid" is a required scope for OpenID Connect flows.
    101 		//
    102 		// Other scopes, such as "groups" can be requested.
    103 		Scopes: scopes,
    104 	}
    105 
    106 	// create a config for verifier creation
    107 	oidcConf := &oidc.Config{
    108 		ClientID: clientID,
    109 	}
    110 
    111 	if config.GetOIDCSkipVerification() {
    112 		oidcConf.SkipClientIDCheck = true
    113 		oidcConf.SkipExpiryCheck = true
    114 		oidcConf.SkipIssuerCheck = true
    115 	}
    116 
    117 	return &idp{
    118 		oauth2Config: oauth2Config,
    119 		oidcConf:     oidcConf,
    120 		provider:     provider,
    121 	}, nil
    122 }