mirror of
https://github.com/1f349/lavender.git
synced 2024-11-09 22:32:48 +00:00
Allowed client specific perms
This commit is contained in:
parent
1940f2de71
commit
6f16ea6690
@ -11,6 +11,10 @@ type Conf struct {
|
||||
ServiceName string `json:"service_name"`
|
||||
Issuer string `json:"issuer"`
|
||||
SsoServices []issuer.SsoConfig `json:"sso_services"`
|
||||
AllowedClients []utils.JsonUrl `json:"allowed_clients"`
|
||||
Permissions []string `json:"permissions"`
|
||||
AllowedClients []AllowedClient `json:"allowed_clients"`
|
||||
}
|
||||
|
||||
type AllowedClient struct {
|
||||
Url utils.JsonUrl `json:"url"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
|
||||
loginUn := loginName[:n]
|
||||
|
||||
targetOrigin := req.PostFormValue("origin")
|
||||
if _, found := h.services[targetOrigin]; !found {
|
||||
allowedService, found := h.services[targetOrigin]
|
||||
if !found {
|
||||
http.Error(rw, "Invalid target origin", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@ -60,7 +61,7 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
|
||||
state := login.Config.Namespace + ":" + uuidNewStringState()
|
||||
h.flowState.Set(state, flowStateData{
|
||||
login,
|
||||
targetOrigin,
|
||||
allowedService,
|
||||
}, time.Now().Add(15*time.Minute))
|
||||
|
||||
// generate oauth2 config and redirect to authorize URL
|
||||
@ -128,26 +129,36 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h
|
||||
return
|
||||
}
|
||||
|
||||
var needsMailFlag bool
|
||||
|
||||
ps := claims.NewPermStorage()
|
||||
for _, i := range h.conf.Permissions {
|
||||
ps.Set(i)
|
||||
for _, i := range v.target.Permissions {
|
||||
if strings.HasPrefix(i, "dynamic:") {
|
||||
if i == "dynamic:mail-client" {
|
||||
needsMailFlag = true
|
||||
}
|
||||
} else {
|
||||
ps.Set(i)
|
||||
}
|
||||
}
|
||||
|
||||
if verified, ok := v3["email_verified"].(bool); ok && verified {
|
||||
if mailAddress, ok := v3["email"].(string); ok {
|
||||
address, err := mail.ParseAddress(mailAddress)
|
||||
if err != nil {
|
||||
http.Error(rw, "Invalid email in userinfo", http.StatusInternalServerError)
|
||||
return
|
||||
if needsMailFlag {
|
||||
if verified, ok := v3["email_verified"].(bool); ok && verified {
|
||||
if mailAddress, ok := v3["email"].(string); ok {
|
||||
address, err := mail.ParseAddress(mailAddress)
|
||||
if err != nil {
|
||||
http.Error(rw, "Invalid email in userinfo", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
n := strings.IndexByte(address.Address, '@')
|
||||
if n == -1 {
|
||||
goto noEmailSupport
|
||||
}
|
||||
if address.Address[n+1:] != v.sso.Config.Namespace {
|
||||
goto noEmailSupport
|
||||
}
|
||||
ps.Set("mail-client")
|
||||
}
|
||||
n := strings.IndexByte(address.Address, '@')
|
||||
if n == -1 {
|
||||
goto noEmailSupport
|
||||
}
|
||||
if address.Address[n+1:] != v.sso.Config.Namespace {
|
||||
goto noEmailSupport
|
||||
}
|
||||
ps.Set("mail-client")
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +181,7 @@ noEmailSupport:
|
||||
|
||||
pages.RenderPageTemplate(rw, "flow-callback", map[string]any{
|
||||
"ServiceName": h.conf.ServiceName,
|
||||
"TargetOrigin": v.targetOrigin,
|
||||
"TargetOrigin": v.target.Url.String(),
|
||||
"TargetMessage": v3,
|
||||
"AccessToken": accessToken,
|
||||
"RefreshToken": refreshToken,
|
||||
|
@ -29,6 +29,8 @@ const lavenderDomain = "http://localhost:0"
|
||||
const clientAppDomain = "http://localhost:1"
|
||||
const loginDomain = "http://localhost:2"
|
||||
|
||||
var clientAppMeta AllowedClient
|
||||
|
||||
var testSigner mjwt.Signer
|
||||
|
||||
var testOidc = &issuer.WellKnownOIDC{
|
||||
@ -70,7 +72,7 @@ var testHttpServer = HttpServer{
|
||||
},
|
||||
manager: testManager,
|
||||
flowState: cache.New[string, flowStateData](),
|
||||
services: map[string]struct{}{
|
||||
services: map[string]AllowedClient{
|
||||
clientAppDomain: {},
|
||||
},
|
||||
}
|
||||
@ -88,6 +90,16 @@ func init() {
|
||||
|
||||
testSigner = mjwt.NewMJwtSigner("https://example.com", key)
|
||||
testHttpServer.signer = testSigner
|
||||
|
||||
parse, err := url.Parse(clientAppDomain)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
clientAppMeta = AllowedClient{
|
||||
Url: utils.JsonUrl{URL: parse},
|
||||
Permissions: []string{"test-perm"},
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlowPopup(t *testing.T) {
|
||||
@ -168,8 +180,8 @@ func TestFlowCallback(t *testing.T) {
|
||||
expiryTime := time.Now().Add(15 * time.Minute)
|
||||
nextState := uuid.NewString()
|
||||
testHttpServer.flowState.Set("example.com:"+nextState, flowStateData{
|
||||
sso: testOidc,
|
||||
targetOrigin: clientAppDomain,
|
||||
sso: testOidc,
|
||||
target: clientAppMeta,
|
||||
}, expiryTime)
|
||||
|
||||
testOa2Exchange = func(oa2conf oauth2.Config, ctx context.Context, code string) (*oauth2.Token, error) {
|
||||
|
@ -17,12 +17,12 @@ type HttpServer struct {
|
||||
manager *issuer.Manager
|
||||
signer mjwt.Signer
|
||||
flowState *cache.Cache[string, flowStateData]
|
||||
services map[string]struct{}
|
||||
services map[string]AllowedClient
|
||||
}
|
||||
|
||||
type flowStateData struct {
|
||||
sso *issuer.WellKnownOIDC
|
||||
targetOrigin string
|
||||
sso *issuer.WellKnownOIDC
|
||||
target AllowedClient
|
||||
}
|
||||
|
||||
func NewHttpServer(conf Conf, signer mjwt.Signer) *http.Server {
|
||||
@ -41,9 +41,9 @@ func NewHttpServer(conf Conf, signer mjwt.Signer) *http.Server {
|
||||
log.Fatal("[Lavender] Failed to create SSO service manager: ", err)
|
||||
}
|
||||
|
||||
services := make(map[string]struct{})
|
||||
services := make(map[string]AllowedClient)
|
||||
for _, i := range conf.AllowedClients {
|
||||
services[i.String()] = struct{}{}
|
||||
services[i.Url.String()] = i
|
||||
}
|
||||
|
||||
hs := &HttpServer{
|
||||
|
Loading…
Reference in New Issue
Block a user