Allowed client specific perms

This commit is contained in:
Melon 2023-10-26 11:30:04 +01:00
parent 1940f2de71
commit 6f16ea6690
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
4 changed files with 56 additions and 29 deletions

View File

@ -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"`
}

View File

@ -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,

View File

@ -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) {

View File

@ -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{