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"`
|
ServiceName string `json:"service_name"`
|
||||||
Issuer string `json:"issuer"`
|
Issuer string `json:"issuer"`
|
||||||
SsoServices []issuer.SsoConfig `json:"sso_services"`
|
SsoServices []issuer.SsoConfig `json:"sso_services"`
|
||||||
AllowedClients []utils.JsonUrl `json:"allowed_clients"`
|
AllowedClients []AllowedClient `json:"allowed_clients"`
|
||||||
Permissions []string `json:"permissions"`
|
}
|
||||||
|
|
||||||
|
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]
|
loginUn := loginName[:n]
|
||||||
|
|
||||||
targetOrigin := req.PostFormValue("origin")
|
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)
|
http.Error(rw, "Invalid target origin", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -60,7 +61,7 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
state := login.Config.Namespace + ":" + uuidNewStringState()
|
state := login.Config.Namespace + ":" + uuidNewStringState()
|
||||||
h.flowState.Set(state, flowStateData{
|
h.flowState.Set(state, flowStateData{
|
||||||
login,
|
login,
|
||||||
targetOrigin,
|
allowedService,
|
||||||
}, time.Now().Add(15*time.Minute))
|
}, time.Now().Add(15*time.Minute))
|
||||||
|
|
||||||
// generate oauth2 config and redirect to authorize URL
|
// generate oauth2 config and redirect to authorize URL
|
||||||
@ -128,26 +129,36 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var needsMailFlag bool
|
||||||
|
|
||||||
ps := claims.NewPermStorage()
|
ps := claims.NewPermStorage()
|
||||||
for _, i := range h.conf.Permissions {
|
for _, i := range v.target.Permissions {
|
||||||
ps.Set(i)
|
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 needsMailFlag {
|
||||||
if mailAddress, ok := v3["email"].(string); ok {
|
if verified, ok := v3["email_verified"].(bool); ok && verified {
|
||||||
address, err := mail.ParseAddress(mailAddress)
|
if mailAddress, ok := v3["email"].(string); ok {
|
||||||
if err != nil {
|
address, err := mail.ParseAddress(mailAddress)
|
||||||
http.Error(rw, "Invalid email in userinfo", http.StatusInternalServerError)
|
if err != nil {
|
||||||
return
|
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{
|
pages.RenderPageTemplate(rw, "flow-callback", map[string]any{
|
||||||
"ServiceName": h.conf.ServiceName,
|
"ServiceName": h.conf.ServiceName,
|
||||||
"TargetOrigin": v.targetOrigin,
|
"TargetOrigin": v.target.Url.String(),
|
||||||
"TargetMessage": v3,
|
"TargetMessage": v3,
|
||||||
"AccessToken": accessToken,
|
"AccessToken": accessToken,
|
||||||
"RefreshToken": refreshToken,
|
"RefreshToken": refreshToken,
|
||||||
|
@ -29,6 +29,8 @@ const lavenderDomain = "http://localhost:0"
|
|||||||
const clientAppDomain = "http://localhost:1"
|
const clientAppDomain = "http://localhost:1"
|
||||||
const loginDomain = "http://localhost:2"
|
const loginDomain = "http://localhost:2"
|
||||||
|
|
||||||
|
var clientAppMeta AllowedClient
|
||||||
|
|
||||||
var testSigner mjwt.Signer
|
var testSigner mjwt.Signer
|
||||||
|
|
||||||
var testOidc = &issuer.WellKnownOIDC{
|
var testOidc = &issuer.WellKnownOIDC{
|
||||||
@ -70,7 +72,7 @@ var testHttpServer = HttpServer{
|
|||||||
},
|
},
|
||||||
manager: testManager,
|
manager: testManager,
|
||||||
flowState: cache.New[string, flowStateData](),
|
flowState: cache.New[string, flowStateData](),
|
||||||
services: map[string]struct{}{
|
services: map[string]AllowedClient{
|
||||||
clientAppDomain: {},
|
clientAppDomain: {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -88,6 +90,16 @@ func init() {
|
|||||||
|
|
||||||
testSigner = mjwt.NewMJwtSigner("https://example.com", key)
|
testSigner = mjwt.NewMJwtSigner("https://example.com", key)
|
||||||
testHttpServer.signer = testSigner
|
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) {
|
func TestFlowPopup(t *testing.T) {
|
||||||
@ -168,8 +180,8 @@ func TestFlowCallback(t *testing.T) {
|
|||||||
expiryTime := time.Now().Add(15 * time.Minute)
|
expiryTime := time.Now().Add(15 * time.Minute)
|
||||||
nextState := uuid.NewString()
|
nextState := uuid.NewString()
|
||||||
testHttpServer.flowState.Set("example.com:"+nextState, flowStateData{
|
testHttpServer.flowState.Set("example.com:"+nextState, flowStateData{
|
||||||
sso: testOidc,
|
sso: testOidc,
|
||||||
targetOrigin: clientAppDomain,
|
target: clientAppMeta,
|
||||||
}, expiryTime)
|
}, expiryTime)
|
||||||
|
|
||||||
testOa2Exchange = func(oa2conf oauth2.Config, ctx context.Context, code string) (*oauth2.Token, error) {
|
testOa2Exchange = func(oa2conf oauth2.Config, ctx context.Context, code string) (*oauth2.Token, error) {
|
||||||
|
@ -17,12 +17,12 @@ type HttpServer struct {
|
|||||||
manager *issuer.Manager
|
manager *issuer.Manager
|
||||||
signer mjwt.Signer
|
signer mjwt.Signer
|
||||||
flowState *cache.Cache[string, flowStateData]
|
flowState *cache.Cache[string, flowStateData]
|
||||||
services map[string]struct{}
|
services map[string]AllowedClient
|
||||||
}
|
}
|
||||||
|
|
||||||
type flowStateData struct {
|
type flowStateData struct {
|
||||||
sso *issuer.WellKnownOIDC
|
sso *issuer.WellKnownOIDC
|
||||||
targetOrigin string
|
target AllowedClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttpServer(conf Conf, signer mjwt.Signer) *http.Server {
|
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)
|
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 {
|
for _, i := range conf.AllowedClients {
|
||||||
services[i.String()] = struct{}{}
|
services[i.Url.String()] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
hs := &HttpServer{
|
hs := &HttpServer{
|
||||||
|
Loading…
Reference in New Issue
Block a user