66 lines
2.3 KiB
Go
66 lines
2.3 KiB
Go
package identityprovider
|
|
|
|
import (
|
|
"errors"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"vpn-platform/backend/internal/model"
|
|
"vpn-platform/backend/internal/service"
|
|
"vpn-platform/backend/internal/store"
|
|
)
|
|
|
|
// builtinTunnel finds the one tunnel whose OAuth callback owns this redirect.
|
|
// Ambiguous or missing routes fail closed; a browser redirect alone grants nothing.
|
|
func builtinTunnel(redirect, base string, cfg model.IdentityProvider) (model.Tunnel, map[string]interface{}, error) {
|
|
u, err := url.Parse(redirect)
|
|
if err != nil || u.RawQuery != "" || u.Fragment != "" || u.Path != "/oauth2/callback" {
|
|
return model.Tunnel{}, nil, errors.New("unknown callback")
|
|
}
|
|
var tunnels []model.Tunnel
|
|
if err := store.DB.Where("protocol = ?", "openvpn").Find(&tunnels).Error; err != nil {
|
|
return model.Tunnel{}, nil, err
|
|
}
|
|
var match model.Tunnel
|
|
var config map[string]interface{}
|
|
for _, tunnel := range tunnels {
|
|
data, err := store.TunnelConfig(&tunnel)
|
|
if err != nil {
|
|
return model.Tunnel{}, nil, err
|
|
}
|
|
if service.Str(data, "auth_mode") != "oidc" || service.Str(data, "oidc_provider") != "builtin" || service.Str(data, "oidc_issuer") != base || service.Str(data, "oidc_client_id") != cfg.ClientID || strings.TrimRight(service.Str(data, "oidc_base_url"), "/")+"/oauth2/callback" != redirect {
|
|
continue
|
|
}
|
|
if match.ID != 0 {
|
|
return model.Tunnel{}, nil, errors.New("ambiguous callback")
|
|
}
|
|
match, config = tunnel, data
|
|
}
|
|
if match.ID == 0 {
|
|
return model.Tunnel{}, nil, errors.New("unknown callback")
|
|
}
|
|
return match, config, nil
|
|
}
|
|
|
|
func admitted(redirect, base string, cfg model.IdentityProvider, subject string) (bool, error) {
|
|
tunnel, config, err := builtinTunnel(redirect, base, cfg)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if raw, present := config["feishu_access_mode"]; present {
|
|
if _, ok := raw.(string); !ok {
|
|
return false, errors.New("invalid admission mode")
|
|
}
|
|
}
|
|
switch service.Str(config, "feishu_access_mode") {
|
|
case "", "all":
|
|
return true, nil
|
|
case "allowlist":
|
|
var count int64
|
|
err := store.DB.Model(&model.FeishuTunnelGrant{}).Where("tunnel_id = ? AND issuer = ? AND app_id = ? AND subject = ?", tunnel.ID, base, cfg.AppID, subject).Count(&count).Error
|
|
return err == nil && count == 1, err
|
|
default:
|
|
return false, errors.New("invalid admission mode")
|
|
}
|
|
}
|