Fix Fortinet SSO again

This commit is contained in:
世界
2026-07-22 22:03:58 +08:00
parent e013b424fc
commit ceb7154384
13 changed files with 110 additions and 41 deletions
+2
View File
@@ -32,6 +32,8 @@ type V2RayServer interface {
type CacheFile interface {
LifecycleService
CacheID() string
StoreFakeIP() bool
FakeIPStorage
+7 -4
View File
@@ -52,10 +52,13 @@ type OpenConnectAuthForm struct {
}
type OpenConnectBrowserRequest struct {
URL string
FinalURL string
CookieNames []string
HeaderNames []string
URL string
FinalURL string
CookieNames []string
EarlyCookieNames []string
HeaderNames []string
CallbackURLPrefixes []string
CacheID string
}
type OpenConnectBrowserCookie struct {
+2 -2
View File
@@ -163,14 +163,14 @@ func buildAndroid() {
bindTarget := getAndroidBindTarget()
// Build main variant (SDK 23)
// Build main variant (SDK 24)
mainTags := append([]string{}, sharedTags...)
// mainTags = append(mainTags, memcTags...)
if debugEnabled {
mainTags = append(mainTags, debugTags...)
}
buildAndroidVariant(AndroidBuildConfig{
AndroidAPI: 23,
AndroidAPI: 24,
OutputName: "libbox.aar",
Tags: mainTags,
}, bindTarget)
+7 -4
View File
@@ -1649,10 +1649,13 @@ func openConnectEndpointStatusToProto(tag string, endpointStatus adapter.OpenCon
}
if endpointStatus.AuthChallenge.Browser != nil {
challenge.Challenge = &OpenConnectAuthChallenge_Browser{Browser: &OpenConnectBrowserRequest{
Url: endpointStatus.AuthChallenge.Browser.URL,
FinalURL: endpointStatus.AuthChallenge.Browser.FinalURL,
CookieNames: endpointStatus.AuthChallenge.Browser.CookieNames,
HeaderNames: endpointStatus.AuthChallenge.Browser.HeaderNames,
Url: endpointStatus.AuthChallenge.Browser.URL,
FinalURL: endpointStatus.AuthChallenge.Browser.FinalURL,
CookieNames: endpointStatus.AuthChallenge.Browser.CookieNames,
EarlyCookieNames: endpointStatus.AuthChallenge.Browser.EarlyCookieNames,
HeaderNames: endpointStatus.AuthChallenge.Browser.HeaderNames,
CallbackURLPrefixes: endpointStatus.AuthChallenge.Browser.CallbackURLPrefixes,
CacheID: endpointStatus.AuthChallenge.Browser.CacheID,
}}
}
result.AuthChallenge = challenge
+36 -9
View File
@@ -5149,13 +5149,16 @@ func (x *OpenConnectAuthFormChoice) GetLabel() string {
}
type OpenConnectBrowserRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
FinalURL string `protobuf:"bytes,2,opt,name=finalURL,proto3" json:"finalURL,omitempty"`
CookieNames []string `protobuf:"bytes,3,rep,name=cookieNames,proto3" json:"cookieNames,omitempty"`
HeaderNames []string `protobuf:"bytes,4,rep,name=headerNames,proto3" json:"headerNames,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
FinalURL string `protobuf:"bytes,2,opt,name=finalURL,proto3" json:"finalURL,omitempty"`
CookieNames []string `protobuf:"bytes,3,rep,name=cookieNames,proto3" json:"cookieNames,omitempty"`
HeaderNames []string `protobuf:"bytes,4,rep,name=headerNames,proto3" json:"headerNames,omitempty"`
CallbackURLPrefixes []string `protobuf:"bytes,5,rep,name=callbackURLPrefixes,proto3" json:"callbackURLPrefixes,omitempty"`
EarlyCookieNames []string `protobuf:"bytes,6,rep,name=earlyCookieNames,proto3" json:"earlyCookieNames,omitempty"`
CacheID string `protobuf:"bytes,7,opt,name=cacheID,proto3" json:"cacheID,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OpenConnectBrowserRequest) Reset() {
@@ -5216,6 +5219,27 @@ func (x *OpenConnectBrowserRequest) GetHeaderNames() []string {
return nil
}
func (x *OpenConnectBrowserRequest) GetCallbackURLPrefixes() []string {
if x != nil {
return x.CallbackURLPrefixes
}
return nil
}
func (x *OpenConnectBrowserRequest) GetEarlyCookieNames() []string {
if x != nil {
return x.EarlyCookieNames
}
return nil
}
func (x *OpenConnectBrowserRequest) GetCacheID() string {
if x != nil {
return x.CacheID
}
return ""
}
type OpenConnectBrowserCookie struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
@@ -6492,12 +6516,15 @@ const file_daemon_started_service_proto_rawDesc = "" +
"\aoptions\x18\x06 \x03(\v2!.daemon.OpenConnectAuthFormChoiceR\aoptions\"G\n" +
"\x19OpenConnectAuthFormChoice\x12\x14\n" +
"\x05value\x18\x01 \x01(\tR\x05value\x12\x14\n" +
"\x05label\x18\x02 \x01(\tR\x05label\"\x8d\x01\n" +
"\x05label\x18\x02 \x01(\tR\x05label\"\x85\x02\n" +
"\x19OpenConnectBrowserRequest\x12\x10\n" +
"\x03url\x18\x01 \x01(\tR\x03url\x12\x1a\n" +
"\bfinalURL\x18\x02 \x01(\tR\bfinalURL\x12 \n" +
"\vcookieNames\x18\x03 \x03(\tR\vcookieNames\x12 \n" +
"\vheaderNames\x18\x04 \x03(\tR\vheaderNames\"D\n" +
"\vheaderNames\x18\x04 \x03(\tR\vheaderNames\x120\n" +
"\x13callbackURLPrefixes\x18\x05 \x03(\tR\x13callbackURLPrefixes\x12*\n" +
"\x10earlyCookieNames\x18\x06 \x03(\tR\x10earlyCookieNames\x12\x18\n" +
"\acacheID\x18\a \x01(\tR\acacheID\"D\n" +
"\x18OpenConnectBrowserCookie\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value\"F\n" +
+3
View File
@@ -582,6 +582,9 @@ message OpenConnectBrowserRequest {
string finalURL = 2;
repeated string cookieNames = 3;
repeated string headerNames = 4;
repeated string callbackURLPrefixes = 5;
repeated string earlyCookieNames = 6;
string cacheID = 7;
}
message OpenConnectBrowserCookie {
+2 -2
View File
@@ -415,9 +415,9 @@ Disable AnyConnect XML POST authentication and start authentication with the leg
### external_auth_disabled
Disable external browser authentication such as SSO and SAML for AnyConnect and GlobalProtect.
Disable external browser authentication such as SSO and SAML for AnyConnect, GlobalProtect, and Fortinet.
When enabled, external authentication is not advertised to the server and an unexpected external authentication request is rejected.
When enabled, external authentication is not advertised for AnyConnect or GlobalProtect, and any unexpected external authentication request, including Fortinet SAML, is rejected.
### password_authentication_disabled
@@ -415,9 +415,9 @@ AnyConnect 压缩模式,可选值为:
### external_auth_disabled
禁用 AnyConnectGlobalProtect 的 SSO、SAML 等外部浏览器认证。
禁用 AnyConnectGlobalProtect 和 Fortinet 的 SSO、SAML 等外部浏览器认证。
启用时不会向服务器声明外部认证支持,并会拒绝意外收到的外部认证请求。
启用时不会为 AnyConnect 或 GlobalProtect 向服务器声明外部认证支持,并会拒绝任何意外收到的外部认证请求,包括 Fortinet SAML
### password_authentication_disabled
+6
View File
@@ -45,6 +45,7 @@ type CacheFile struct {
logger logger.Logger
path string
cacheID []byte
cacheIDText string
storeFakeIP bool
storeRDRC bool
storeDNS bool
@@ -104,6 +105,7 @@ func New(ctx context.Context, logger logger.Logger, options option.CacheFileOpti
logger: logger,
path: filemanager.BasePath(ctx, path),
cacheID: cacheIDBytes,
cacheIDText: options.CacheID,
storeFakeIP: options.StoreFakeIP,
storeRDRC: options.StoreRDRC,
storeDNS: options.StoreDNS,
@@ -124,6 +126,10 @@ func (c *CacheFile) Dependencies() []string {
return nil
}
func (c *CacheFile) CacheID() string {
return c.cacheIDText
}
func (c *CacheFile) SetOptimisticTimeout(timeout time.Duration) {
c.optimisticTimeout = timeout
}
@@ -1,6 +1,8 @@
package libbox
import (
"strings"
"github.com/sagernet/sing-box/daemon"
"github.com/sagernet/sing/common"
)
@@ -68,20 +70,31 @@ func (f *OpenConnectAuthForm) Fields() OpenConnectAuthFormFieldIterator {
}
type OpenConnectBrowserRequest struct {
URL string
FinalURL string
cookieNames []string
headerNames []string
URL string
FinalURL string
CacheID string
cookieNames []string
earlyCookieNames []string
headerNames []string
callbackURLPrefixes []string
}
func (r *OpenConnectBrowserRequest) CookieNames() StringIterator {
return newIterator(r.cookieNames)
}
func (r *OpenConnectBrowserRequest) EarlyCookieNames() StringIterator {
return newIterator(r.earlyCookieNames)
}
func (r *OpenConnectBrowserRequest) HeaderNames() StringIterator {
return newIterator(r.headerNames)
}
func (r *OpenConnectBrowserRequest) CallbackURLPrefixes() StringIterator {
return newIterator(r.callbackURLPrefixes)
}
type OpenConnectAuthFormFieldIterator interface {
Next() *OpenConnectAuthFormField
HasNext() bool
@@ -137,9 +150,9 @@ func (r *OpenConnectBrowserResult) AddCookie(name string, value string) {
}
func (r *OpenConnectBrowserResult) AddHeader(name string, value string) {
for _, header := range r.headers {
if header.Name == name {
header.Values = append(header.Values, value)
for i := range r.headers {
if strings.EqualFold(r.headers[i].Name, name) {
r.headers[i].Values = append(r.headers[i].Values, value)
return
}
}
@@ -221,10 +234,13 @@ func openConnectEndpointStatusFromGRPC(status *daemon.OpenConnectEndpointStatus)
browser := status.AuthChallenge.GetBrowser()
if browser != nil {
challenge.Browser = &OpenConnectBrowserRequest{
URL: browser.Url,
FinalURL: browser.FinalURL,
cookieNames: browser.CookieNames,
headerNames: browser.HeaderNames,
URL: browser.Url,
FinalURL: browser.FinalURL,
CacheID: browser.CacheID,
cookieNames: browser.CookieNames,
earlyCookieNames: browser.EarlyCookieNames,
headerNames: browser.HeaderNames,
callbackURLPrefixes: browser.CallbackURLPrefixes,
}
}
result.AuthChallenge = challenge
+1 -1
View File
@@ -46,7 +46,7 @@ require (
github.com/sagernet/sing v0.8.12-0.20260721063414-596db5dd6ef4
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3
github.com/sagernet/sing-mux v0.3.5
github.com/sagernet/sing-openconnect v0.0.0-20260721123934-0d945d43288f
github.com/sagernet/sing-openconnect v0.0.0-20260722140139-e0c977659ca2
github.com/sagernet/sing-openvpn v0.0.0-20260721005523-64b754d1c277
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31
github.com/sagernet/sing-shadowsocks v0.2.8
+2 -2
View File
@@ -317,8 +317,8 @@ github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 h1:3y6
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg=
github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI=
github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
github.com/sagernet/sing-openconnect v0.0.0-20260721123934-0d945d43288f h1:FKT5eCVyNiRNpa5jov6Fl9aQpAgKuCmkuhqVXvBK8b4=
github.com/sagernet/sing-openconnect v0.0.0-20260721123934-0d945d43288f/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg=
github.com/sagernet/sing-openconnect v0.0.0-20260722140139-e0c977659ca2 h1:IOzb7F/NRhAKx49+8HEsJmKrZT73EPseFouxQ6MvAOo=
github.com/sagernet/sing-openconnect v0.0.0-20260722140139-e0c977659ca2/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg=
github.com/sagernet/sing-openvpn v0.0.0-20260721005523-64b754d1c277 h1:4H38L3OxOx1fGEuH4n9lh/5O7XtZTgQ/1V/gdQ+b+Es=
github.com/sagernet/sing-openvpn v0.0.0-20260721005523-64b754d1c277/go.mod h1:PWX7WygD8jpwfqfaGNySXpJYTn0SOwjBI1BKHHC2+Bw=
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31 h1:FuiTs45PaA1/f2Kj6E2QlctFBrJUUFB8QAHnV5im9c8=
+13 -4
View File
@@ -7,6 +7,7 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-openconnect"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/service"
)
var _ adapter.OpenConnectEndpoint = (*Endpoint)(nil)
@@ -45,11 +46,19 @@ func (e *Endpoint) OpenConnectStatus() adapter.OpenConnectStatus {
}
}
if authChallenge.Browser != nil {
var cacheID string
cacheFile := service.FromContext[adapter.CacheFile](e.loopContext)
if cacheFile != nil {
cacheID = cacheFile.CacheID()
}
challenge.Browser = &adapter.OpenConnectBrowserRequest{
URL: authChallenge.Browser.URL,
FinalURL: authChallenge.Browser.FinalURL,
CookieNames: slices.Clone(authChallenge.Browser.CookieNames),
HeaderNames: slices.Clone(authChallenge.Browser.HeaderNames),
URL: authChallenge.Browser.URL,
FinalURL: authChallenge.Browser.FinalURL,
CookieNames: slices.Clone(authChallenge.Browser.CookieNames),
EarlyCookieNames: slices.Clone(authChallenge.Browser.EarlyCookieNames),
HeaderNames: slices.Clone(authChallenge.Browser.HeaderNames),
CallbackURLPrefixes: slices.Clone(authChallenge.Browser.CallbackURLPrefixes),
CacheID: cacheID,
}
}
status.AuthChallenge = challenge