1
1
mirror of https://github.com/go-gitea/gitea synced 2024-07-07 10:35:48 +00:00
gitea/services/externalaccount/user.go
techknowlogick 5bb8d1924d
Support SAML authentication (#25165)
Closes https://github.com/go-gitea/gitea/issues/5512

This PR adds basic SAML support
- Adds SAML 2.0 as an auth source
- Adds SAML configuration documentation
- Adds integration test:
- Use bare-bones SAML IdP to test protocol flow and test account is
linked successfully (only runs on Postgres by default)
- Adds documentation for configuring and running SAML integration test
locally

Future PRs:
- Support group mapping
- Support auto-registration (account linking)

Co-Authored-By: @jackHay22

---------

Co-authored-by: jackHay22 <jack@allspice.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: morphelinho <morphelinho@users.noreply.github.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: Yarden Shoham <git@yardenshoham.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: silverwind <me@silverwind.io>
2024-02-23 00:08:17 +00:00

102 lines
3.2 KiB
Go

// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package externalaccount
import (
"context"
"strings"
"code.gitea.io/gitea/models/auth"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/structs"
"github.com/markbates/goth"
)
func toExternalLoginUser(ctx context.Context, user *user_model.User, gothUser goth.User, authType auth.Type) (*user_model.ExternalLoginUser, error) {
authSource, err := auth.GetActiveAuthSourceByName(ctx, gothUser.Provider, authType)
if err != nil {
return nil, err
}
return &user_model.ExternalLoginUser{
ExternalID: gothUser.UserID,
UserID: user.ID,
LoginSourceID: authSource.ID,
RawData: gothUser.RawData,
Provider: gothUser.Provider,
Email: gothUser.Email,
Name: gothUser.Name,
FirstName: gothUser.FirstName,
LastName: gothUser.LastName,
NickName: gothUser.NickName,
Description: gothUser.Description,
AvatarURL: gothUser.AvatarURL,
Location: gothUser.Location,
AccessToken: gothUser.AccessToken,
AccessTokenSecret: gothUser.AccessTokenSecret,
RefreshToken: gothUser.RefreshToken,
ExpiresAt: gothUser.ExpiresAt,
}, nil
}
// LinkAccountToUser link the gothUser to the user
func LinkAccountToUser(ctx context.Context, user *user_model.User, gothUser goth.User, authType auth.Type) error {
externalLoginUser, err := toExternalLoginUser(ctx, user, gothUser, authType)
if err != nil {
return err
}
if err := user_model.LinkExternalToUser(ctx, user, externalLoginUser); err != nil {
return err
}
externalID := externalLoginUser.ExternalID
var tp structs.GitServiceType
for _, s := range structs.SupportedFullGitService {
if strings.EqualFold(s.Name(), gothUser.Provider) {
tp = s
break
}
}
if tp.Name() != "" {
return UpdateMigrationsByType(ctx, tp, externalID, user.ID)
}
return nil
}
// UpdateExternalUser updates external user's information
func UpdateExternalUser(ctx context.Context, user *user_model.User, gothUser goth.User, authType auth.Type) error {
externalLoginUser, err := toExternalLoginUser(ctx, user, gothUser, authType)
if err != nil {
return err
}
return user_model.UpdateExternalUserByExternalID(ctx, externalLoginUser)
}
// UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID
func UpdateMigrationsByType(ctx context.Context, tp structs.GitServiceType, externalUserID string, userID int64) error {
if err := issues_model.UpdateIssuesMigrationsByType(ctx, tp, externalUserID, userID); err != nil {
return err
}
if err := issues_model.UpdateCommentsMigrationsByType(ctx, tp, externalUserID, userID); err != nil {
return err
}
if err := repo_model.UpdateReleasesMigrationsByType(ctx, tp, externalUserID, userID); err != nil {
return err
}
if err := issues_model.UpdateReactionsMigrationsByType(ctx, tp, externalUserID, userID); err != nil {
return err
}
return issues_model.UpdateReviewsMigrationsByType(ctx, tp, externalUserID, userID)
}