3642be6f21
* client: always parse the json error message field and return its contents * Use ErrBadRequest and ErrNotFound in every handler and command * Gateway: by default pass underlying service error (configstore, runservice) to client keeping the status code and message. In future, if some errors must be masked, we should change the specific parts that need special handling.
608 lines
19 KiB
Go
608 lines
19 KiB
Go
// Copyright 2019 Sorint.lab
|
|
//
|
|
// Licensed 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 command
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
gitsource "github.com/sorintlab/agola/internal/gitsources"
|
|
csapi "github.com/sorintlab/agola/internal/services/configstore/api"
|
|
"github.com/sorintlab/agola/internal/services/gateway/common"
|
|
"github.com/sorintlab/agola/internal/services/types"
|
|
"github.com/sorintlab/agola/internal/util"
|
|
|
|
jwt "github.com/dgrijalva/jwt-go"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type CreateUserRequest struct {
|
|
UserName string
|
|
}
|
|
|
|
func (c *CommandHandler) CreateUser(ctx context.Context, req *CreateUserRequest) (*types.User, error) {
|
|
if req.UserName == "" {
|
|
return nil, util.NewErrBadRequest(errors.Errorf("user name required"))
|
|
}
|
|
if !util.ValidateName(req.UserName) {
|
|
return nil, util.NewErrBadRequest(errors.Errorf("invalid user name %q", req.UserName))
|
|
}
|
|
|
|
creq := &csapi.CreateUserRequest{
|
|
UserName: req.UserName,
|
|
}
|
|
|
|
c.log.Infof("creating user")
|
|
u, resp, err := c.configstoreClient.CreateUser(ctx, creq)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to create user"))
|
|
}
|
|
c.log.Infof("user %s created, ID: %s", u.UserName, u.ID)
|
|
|
|
return u, nil
|
|
}
|
|
|
|
type CreateUserTokenRequest struct {
|
|
UserName string
|
|
TokenName string
|
|
}
|
|
|
|
func (c *CommandHandler) CreateUserToken(ctx context.Context, req *CreateUserTokenRequest) (string, error) {
|
|
var userID string
|
|
userIDVal := ctx.Value("userid")
|
|
if userIDVal != nil {
|
|
userID = userIDVal.(string)
|
|
}
|
|
|
|
isAdmin := false
|
|
isAdminVal := ctx.Value("admin")
|
|
if isAdminVal != nil {
|
|
isAdmin = isAdminVal.(bool)
|
|
}
|
|
|
|
userName := req.UserName
|
|
user, resp, err := c.configstoreClient.GetUserByName(ctx, userName)
|
|
if err != nil {
|
|
return "", ErrFromRemote(resp, errors.Wrapf(err, "failed to get user"))
|
|
}
|
|
|
|
// only admin or the same logged user can create a token
|
|
if !isAdmin && user.ID != userID {
|
|
return "", util.NewErrBadRequest(errors.Errorf("logged in user cannot create token for another user"))
|
|
}
|
|
if _, ok := user.Tokens[req.TokenName]; ok {
|
|
return "", util.NewErrBadRequest(errors.Errorf("user %q already have a token with name %q", userName, req.TokenName))
|
|
}
|
|
|
|
c.log.Infof("creating user token")
|
|
creq := &csapi.CreateUserTokenRequest{
|
|
TokenName: req.TokenName,
|
|
}
|
|
res, resp, err := c.configstoreClient.CreateUserToken(ctx, userName, creq)
|
|
if err != nil {
|
|
return "", ErrFromRemote(resp, errors.Wrapf(err, "failed to create user token"))
|
|
}
|
|
c.log.Infof("token %q for user %q created", req.TokenName, userName)
|
|
|
|
return res.Token, nil
|
|
}
|
|
|
|
type CreateUserLARequest struct {
|
|
UserName string
|
|
RemoteSourceName string
|
|
RemoteSourceUserAccessToken string
|
|
RemoteSourceOauth2AccessToken string
|
|
RemoteSourceOauth2RefreshToken string
|
|
}
|
|
|
|
func (c *CommandHandler) CreateUserLA(ctx context.Context, req *CreateUserLARequest) (*types.LinkedAccount, error) {
|
|
userName := req.UserName
|
|
user, resp, err := c.configstoreClient.GetUserByName(ctx, userName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", userName))
|
|
}
|
|
rs, resp, err := c.configstoreClient.GetRemoteSourceByName(ctx, req.RemoteSourceName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName))
|
|
}
|
|
c.log.Infof("rs: %s", util.Dump(rs))
|
|
var la *types.LinkedAccount
|
|
for _, v := range user.LinkedAccounts {
|
|
if v.RemoteSourceID == rs.ID {
|
|
la = v
|
|
break
|
|
}
|
|
}
|
|
c.log.Infof("la: %s", util.Dump(la))
|
|
if la != nil {
|
|
return nil, util.NewErrBadRequest(errors.Errorf("user %q already have a linked account for remote source %q", userName, rs.Name))
|
|
}
|
|
|
|
accessToken, err := common.GetAccessToken(rs.AuthType, req.RemoteSourceUserAccessToken, req.RemoteSourceOauth2AccessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userSource, err := common.GetUserSource(rs, accessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
remoteUserInfo, err := userSource.GetUserInfo()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID)
|
|
}
|
|
if remoteUserInfo.ID == "" {
|
|
return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID)
|
|
}
|
|
|
|
creq := &csapi.CreateUserLARequest{
|
|
RemoteSourceName: req.RemoteSourceName,
|
|
RemoteUserID: remoteUserInfo.ID,
|
|
RemoteUserName: remoteUserInfo.LoginName,
|
|
Oauth2AccessToken: req.RemoteSourceOauth2AccessToken,
|
|
Oauth2RefreshToken: req.RemoteSourceOauth2RefreshToken,
|
|
UserAccessToken: req.RemoteSourceUserAccessToken,
|
|
}
|
|
|
|
c.log.Infof("creating linked account")
|
|
la, resp, err = c.configstoreClient.CreateUserLA(ctx, userName, creq)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to create linked account"))
|
|
}
|
|
c.log.Infof("linked account %q for user %q created", la.ID, userName)
|
|
|
|
return la, nil
|
|
}
|
|
|
|
type RegisterUserRequest struct {
|
|
UserName string
|
|
RemoteSourceName string
|
|
RemoteSourceUserAccessToken string
|
|
RemoteSourceOauth2AccessToken string
|
|
RemoteSourceOauth2RefreshToken string
|
|
}
|
|
|
|
func (c *CommandHandler) RegisterUser(ctx context.Context, req *RegisterUserRequest) (*types.User, error) {
|
|
if req.UserName == "" {
|
|
return nil, util.NewErrBadRequest(errors.Errorf("user name required"))
|
|
}
|
|
if !util.ValidateName(req.UserName) {
|
|
return nil, util.NewErrBadRequest(errors.Errorf("invalid user name %q", req.UserName))
|
|
}
|
|
|
|
rs, resp, err := c.configstoreClient.GetRemoteSourceByName(ctx, req.RemoteSourceName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName))
|
|
}
|
|
c.log.Infof("rs: %s", util.Dump(rs))
|
|
|
|
accessToken, err := common.GetAccessToken(rs.AuthType, req.RemoteSourceUserAccessToken, req.RemoteSourceOauth2AccessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userSource, err := common.GetUserSource(rs, accessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
remoteUserInfo, err := userSource.GetUserInfo()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID)
|
|
}
|
|
if remoteUserInfo.ID == "" {
|
|
return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID)
|
|
}
|
|
|
|
creq := &csapi.CreateUserRequest{
|
|
UserName: req.UserName,
|
|
CreateUserLARequest: &csapi.CreateUserLARequest{
|
|
RemoteSourceName: req.RemoteSourceName,
|
|
RemoteUserID: remoteUserInfo.ID,
|
|
RemoteUserName: remoteUserInfo.LoginName,
|
|
Oauth2AccessToken: req.RemoteSourceOauth2AccessToken,
|
|
Oauth2RefreshToken: req.RemoteSourceOauth2RefreshToken,
|
|
UserAccessToken: req.RemoteSourceUserAccessToken,
|
|
},
|
|
}
|
|
|
|
c.log.Infof("creating user account")
|
|
u, resp, err := c.configstoreClient.CreateUser(ctx, creq)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to create linked account"))
|
|
}
|
|
c.log.Infof("user %q created", req.UserName)
|
|
|
|
return u, nil
|
|
}
|
|
|
|
type LoginUserRequest struct {
|
|
RemoteSourceName string
|
|
RemoteSourceUserAccessToken string
|
|
RemoteSourceOauth2AccessToken string
|
|
RemoteSourceOauth2RefreshToken string
|
|
}
|
|
|
|
type LoginUserResponse struct {
|
|
Token string
|
|
User *types.User
|
|
}
|
|
|
|
func (c *CommandHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (*LoginUserResponse, error) {
|
|
rs, resp, err := c.configstoreClient.GetRemoteSourceByName(ctx, req.RemoteSourceName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName))
|
|
}
|
|
c.log.Infof("rs: %s", util.Dump(rs))
|
|
|
|
accessToken, err := common.GetAccessToken(rs.AuthType, req.RemoteSourceUserAccessToken, req.RemoteSourceOauth2AccessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userSource, err := common.GetUserSource(rs, accessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
remoteUserInfo, err := userSource.GetUserInfo()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID)
|
|
}
|
|
if remoteUserInfo.ID == "" {
|
|
return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID)
|
|
}
|
|
|
|
user, resp, err := c.configstoreClient.GetUserByLinkedAccountRemoteUserAndSource(ctx, remoteUserInfo.ID, rs.ID)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user for remote user id %q and remote source %q", remoteUserInfo.ID, rs.ID))
|
|
}
|
|
|
|
var la *types.LinkedAccount
|
|
for _, v := range user.LinkedAccounts {
|
|
if v.RemoteSourceID == rs.ID {
|
|
la = v
|
|
break
|
|
}
|
|
}
|
|
c.log.Infof("la: %s", util.Dump(la))
|
|
if la == nil {
|
|
return nil, errors.Errorf("linked account for user %q for remote source %q doesn't exist", user.UserName, rs.Name)
|
|
}
|
|
|
|
// Update oauth tokens if they have changed since the getuserinfo request may have updated them
|
|
if la.Oauth2AccessToken != req.RemoteSourceOauth2AccessToken ||
|
|
la.Oauth2RefreshToken != req.RemoteSourceOauth2RefreshToken ||
|
|
la.UserAccessToken != req.RemoteSourceUserAccessToken {
|
|
|
|
la.Oauth2AccessToken = req.RemoteSourceOauth2AccessToken
|
|
la.Oauth2RefreshToken = req.RemoteSourceOauth2RefreshToken
|
|
la.UserAccessToken = req.RemoteSourceUserAccessToken
|
|
|
|
creq := &csapi.UpdateUserLARequest{
|
|
RemoteUserID: la.RemoteUserID,
|
|
RemoteUserName: la.RemoteUserName,
|
|
Oauth2AccessToken: la.Oauth2AccessToken,
|
|
Oauth2RefreshToken: la.Oauth2RefreshToken,
|
|
UserAccessToken: la.UserAccessToken,
|
|
}
|
|
|
|
c.log.Infof("updating user %q linked account", user.UserName)
|
|
la, resp, err = c.configstoreClient.UpdateUserLA(ctx, user.UserName, la.ID, creq)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to update user"))
|
|
}
|
|
c.log.Infof("linked account %q for user %q updated", la.ID, user.UserName)
|
|
}
|
|
|
|
// generate jwt token
|
|
token, err := common.GenerateLoginJWTToken(c.sd, user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &LoginUserResponse{
|
|
Token: token,
|
|
User: user,
|
|
}, nil
|
|
}
|
|
|
|
type AuthorizeRequest struct {
|
|
RemoteSourceName string
|
|
RemoteSourceUserAccessToken string
|
|
RemoteSourceOauth2AccessToken string
|
|
RemoteSourceOauth2RefreshToken string
|
|
}
|
|
|
|
type AuthorizeResponse struct {
|
|
RemoteUserInfo *gitsource.UserInfo
|
|
RemoteSourceName string
|
|
}
|
|
|
|
func (c *CommandHandler) Authorize(ctx context.Context, req *AuthorizeRequest) (*AuthorizeResponse, error) {
|
|
rs, resp, err := c.configstoreClient.GetRemoteSourceByName(ctx, req.RemoteSourceName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", req.RemoteSourceName))
|
|
}
|
|
c.log.Infof("rs: %s", util.Dump(rs))
|
|
|
|
accessToken, err := common.GetAccessToken(rs.AuthType, req.RemoteSourceUserAccessToken, req.RemoteSourceOauth2AccessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userSource, err := common.GetUserSource(rs, accessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
remoteUserInfo, err := userSource.GetUserInfo()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to retrieve remote user info for remote source %q", rs.ID)
|
|
}
|
|
if remoteUserInfo.ID == "" {
|
|
return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID)
|
|
}
|
|
|
|
return &AuthorizeResponse{
|
|
RemoteUserInfo: remoteUserInfo,
|
|
RemoteSourceName: req.RemoteSourceName,
|
|
}, nil
|
|
}
|
|
|
|
type RemoteSourceAuthResponse struct {
|
|
Oauth2Redirect string
|
|
Response interface{}
|
|
}
|
|
|
|
func (c *CommandHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSourceName, loginName, loginPassword string, requestType RemoteSourceRequestType, req interface{}) (*RemoteSourceAuthResponse, error) {
|
|
rs, resp, err := c.configstoreClient.GetRemoteSourceByName(ctx, remoteSourceName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", remoteSourceName))
|
|
}
|
|
c.log.Infof("rs: %s", util.Dump(rs))
|
|
|
|
switch requestType {
|
|
case RemoteSourceRequestTypeCreateUserLA:
|
|
req := req.(*CreateUserLARequest)
|
|
user, resp, err := c.configstoreClient.GetUserByName(ctx, req.UserName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", req.UserName))
|
|
}
|
|
var la *types.LinkedAccount
|
|
for _, v := range user.LinkedAccounts {
|
|
if v.RemoteSourceID == rs.ID {
|
|
la = v
|
|
break
|
|
}
|
|
}
|
|
c.log.Infof("la: %s", util.Dump(la))
|
|
if la != nil {
|
|
return nil, util.NewErrBadRequest(errors.Errorf("user %q already have a linked account for remote source %q", req.UserName, rs.Name))
|
|
}
|
|
|
|
case RemoteSourceRequestTypeLoginUser:
|
|
|
|
case RemoteSourceRequestTypeAuthorize:
|
|
|
|
case RemoteSourceRequestTypeRegisterUser:
|
|
|
|
default:
|
|
return nil, errors.Errorf("unknown request type: %q", requestType)
|
|
}
|
|
|
|
switch rs.AuthType {
|
|
case types.RemoteSourceAuthTypeOauth2:
|
|
oauth2Source, err := common.GetOauth2Source(rs, "")
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to create git source")
|
|
}
|
|
token, err := common.GenerateJWTToken(c.sd, rs.Name, string(requestType), req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
redirect, err := oauth2Source.GetOauth2AuthorizationURL(c.webExposedURL+"/oauth2/callback", token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
c.log.Infof("oauth2 redirect: %s", redirect)
|
|
|
|
return &RemoteSourceAuthResponse{
|
|
Oauth2Redirect: redirect,
|
|
}, nil
|
|
|
|
case types.RemoteSourceAuthTypePassword:
|
|
passwordSource, err := common.GetPasswordSource(rs, "")
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to create git source")
|
|
}
|
|
accessToken, err := passwordSource.LoginPassword(loginName, loginPassword)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to login to remote source %q with login name %q", rs.Name, loginName)
|
|
}
|
|
c.log.Infof("access token: %s", accessToken)
|
|
requestj, err := json.Marshal(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cres, err := c.HandleRemoteSourceAuthRequest(ctx, requestType, string(requestj), accessToken, "", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &RemoteSourceAuthResponse{
|
|
Response: cres.Response,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, errors.Errorf("unknown remote source authentication type: %q", rs.AuthType)
|
|
}
|
|
}
|
|
|
|
type RemoteSourceRequestType string
|
|
|
|
const (
|
|
RemoteSourceRequestTypeCreateUserLA RemoteSourceRequestType = "createuserla"
|
|
RemoteSourceRequestTypeLoginUser RemoteSourceRequestType = "loginuser"
|
|
RemoteSourceRequestTypeAuthorize RemoteSourceRequestType = "authorize"
|
|
RemoteSourceRequestTypeRegisterUser RemoteSourceRequestType = "registeruser"
|
|
)
|
|
|
|
type RemoteSourceAuthResult struct {
|
|
RequestType RemoteSourceRequestType
|
|
Response interface{}
|
|
}
|
|
|
|
type CreateUserLAResponse struct {
|
|
LinkedAccount *types.LinkedAccount
|
|
}
|
|
|
|
func (c *CommandHandler) HandleRemoteSourceAuthRequest(ctx context.Context, requestType RemoteSourceRequestType, requestString string, userAccessToken, Oauth2AccessToken, Oauth2RefreshToken string) (*RemoteSourceAuthResult, error) {
|
|
switch requestType {
|
|
case RemoteSourceRequestTypeCreateUserLA:
|
|
var req *CreateUserLARequest
|
|
if err := json.Unmarshal([]byte(requestString), &req); err != nil {
|
|
return nil, errors.Errorf("failed to unmarshal request")
|
|
}
|
|
|
|
creq := &CreateUserLARequest{
|
|
UserName: req.UserName,
|
|
RemoteSourceName: req.RemoteSourceName,
|
|
RemoteSourceUserAccessToken: userAccessToken,
|
|
RemoteSourceOauth2AccessToken: Oauth2AccessToken,
|
|
RemoteSourceOauth2RefreshToken: Oauth2RefreshToken,
|
|
}
|
|
la, err := c.CreateUserLA(ctx, creq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &RemoteSourceAuthResult{
|
|
RequestType: requestType,
|
|
Response: &CreateUserLAResponse{
|
|
LinkedAccount: la,
|
|
},
|
|
}, nil
|
|
|
|
case RemoteSourceRequestTypeLoginUser:
|
|
var req *LoginUserRequest
|
|
if err := json.Unmarshal([]byte(requestString), &req); err != nil {
|
|
return nil, errors.Errorf("failed to unmarshal request")
|
|
}
|
|
|
|
creq := &LoginUserRequest{
|
|
RemoteSourceName: req.RemoteSourceName,
|
|
RemoteSourceUserAccessToken: userAccessToken,
|
|
RemoteSourceOauth2AccessToken: Oauth2AccessToken,
|
|
RemoteSourceOauth2RefreshToken: Oauth2RefreshToken,
|
|
}
|
|
cresp, err := c.LoginUser(ctx, creq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &RemoteSourceAuthResult{
|
|
RequestType: requestType,
|
|
Response: cresp,
|
|
}, nil
|
|
|
|
case RemoteSourceRequestTypeAuthorize:
|
|
var req *AuthorizeRequest
|
|
if err := json.Unmarshal([]byte(requestString), &req); err != nil {
|
|
return nil, errors.Errorf("failed to unmarshal request")
|
|
}
|
|
|
|
creq := &AuthorizeRequest{
|
|
RemoteSourceName: req.RemoteSourceName,
|
|
RemoteSourceUserAccessToken: userAccessToken,
|
|
RemoteSourceOauth2AccessToken: Oauth2AccessToken,
|
|
RemoteSourceOauth2RefreshToken: Oauth2RefreshToken,
|
|
}
|
|
cresp, err := c.Authorize(ctx, creq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &RemoteSourceAuthResult{
|
|
RequestType: requestType,
|
|
Response: cresp,
|
|
}, nil
|
|
|
|
case RemoteSourceRequestTypeRegisterUser:
|
|
var req *RegisterUserRequest
|
|
if err := json.Unmarshal([]byte(requestString), &req); err != nil {
|
|
return nil, errors.Errorf("failed to unmarshal request")
|
|
}
|
|
|
|
creq := &RegisterUserRequest{
|
|
UserName: req.UserName,
|
|
RemoteSourceName: req.RemoteSourceName,
|
|
RemoteSourceUserAccessToken: userAccessToken,
|
|
RemoteSourceOauth2AccessToken: Oauth2AccessToken,
|
|
RemoteSourceOauth2RefreshToken: Oauth2RefreshToken,
|
|
}
|
|
cresp, err := c.RegisterUser(ctx, creq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &RemoteSourceAuthResult{
|
|
RequestType: requestType,
|
|
Response: cresp,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, errors.Errorf("unknown request")
|
|
}
|
|
}
|
|
|
|
func (c *CommandHandler) HandleOauth2Callback(ctx context.Context, code, state string) (*RemoteSourceAuthResult, error) {
|
|
token, err := jwt.Parse(state, func(token *jwt.Token) (interface{}, error) {
|
|
if token.Method != c.sd.Method {
|
|
return nil, errors.Errorf("unexpected signing method: %v", token.Header["alg"])
|
|
}
|
|
var key interface{}
|
|
switch c.sd.Method {
|
|
case jwt.SigningMethodRS256:
|
|
key = c.sd.PrivateKey
|
|
case jwt.SigningMethodHS256:
|
|
key = c.sd.Key
|
|
default:
|
|
return nil, errors.Errorf("unsupported signing method %q", c.sd.Method.Alg())
|
|
}
|
|
return key, nil
|
|
})
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to parse jwt")
|
|
}
|
|
if !token.Valid {
|
|
return nil, errors.Errorf("invalid token")
|
|
}
|
|
|
|
claims := token.Claims.(jwt.MapClaims)
|
|
remoteSourceName := claims["remote_source_name"].(string)
|
|
requestType := RemoteSourceRequestType(claims["request_type"].(string))
|
|
requestString := claims["request"].(string)
|
|
|
|
rs, resp, err := c.configstoreClient.GetRemoteSourceByName(ctx, remoteSourceName)
|
|
if err != nil {
|
|
return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", remoteSourceName))
|
|
}
|
|
c.log.Infof("rs: %s", util.Dump(rs))
|
|
|
|
oauth2Source, err := common.GetOauth2Source(rs, "")
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to create gitlab source")
|
|
}
|
|
|
|
oauth2Token, err := oauth2Source.RequestOauth2Token(c.webExposedURL+"/oauth2/callback", code)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c.HandleRemoteSourceAuthRequest(ctx, requestType, requestString, "", oauth2Token.AccessToken, oauth2Token.RefreshToken)
|
|
}
|