policy: support emails from directory user (#5504)

This commit is contained in:
Caleb Doxsey 2025-02-27 13:39:28 -07:00 committed by GitHub
parent a70593c424
commit c280119498
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 106 additions and 15 deletions

View file

@ -85,7 +85,8 @@ else := [false, {"user-unauthenticated"}]
domain_0 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
directory_user := get_directory_user(session)
domain := split(get_user_email(session, user, directory_user), "@")[1]
domain == "a.example.com"
}
@ -99,7 +100,8 @@ else := [false, {"user-unauthenticated"}]
domain_1 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
directory_user := get_directory_user(session)
domain := split(get_user_email(session, user, directory_user), "@")[1]
domain == "b.example.com"
}
@ -113,7 +115,8 @@ else := [false, {"user-unauthenticated"}]
domain_2 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
directory_user := get_directory_user(session)
domain := split(get_user_email(session, user, directory_user), "@")[1]
domain == "c.example.com"
}
@ -127,7 +130,8 @@ else := [false, {"user-unauthenticated"}]
domain_3 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
directory_user := get_directory_user(session)
domain := split(get_user_email(session, user, directory_user), "@")[1]
domain == "d.example.com"
}
@ -141,7 +145,8 @@ else := [false, {"user-unauthenticated"}]
domain_4 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
directory_user := get_directory_user(session)
domain := split(get_user_email(session, user, directory_user), "@")[1]
domain == "e.example.com"
}
@ -240,7 +245,8 @@ else := [false, {"user-unauthenticated"}]
email_0 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
directory_user := get_directory_user(session)
email := get_user_email(session, user, directory_user)
email == "user1"
}
@ -267,7 +273,8 @@ else := [false, {"user-unauthenticated"}]
email_1 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
directory_user := get_directory_user(session)
email := get_user_email(session, user, directory_user)
email == "user2"
}
@ -294,7 +301,8 @@ else := [false, {"user-unauthenticated"}]
email_2 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
directory_user := get_directory_user(session)
email := get_user_email(session, user, directory_user)
email == "user3"
}
@ -321,7 +329,8 @@ else := [false, {"user-unauthenticated"}]
email_3 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
directory_user := get_directory_user(session)
email := get_user_email(session, user, directory_user)
email == "user4"
}
@ -348,7 +357,8 @@ else := [false, {"user-unauthenticated"}]
email_4 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
directory_user := get_directory_user(session)
email := get_user_email(session, user, directory_user)
email == "user5"
}
@ -478,7 +488,19 @@ get_user(session) := v if {
else := {}
get_user_email(session, user) := v if {
get_directory_user(session) := v if {
v = get_databroker_record("pomerium.io/DirectoryUser", session.user_id)
v != null
}
else := {}
get_user_email(session, user, directory_user) := v if {
v = object.get(directory_user, "email", "")
v != ""
}
else := v if {
v = user.email
}

View file

@ -15,7 +15,10 @@ var domainBody = ast.Body{
user := get_user(session)
`),
ast.MustParseExpr(`
domain := split(get_user_email(session, user), "@")[1]
directory_user := get_directory_user(session)
`),
ast.MustParseExpr(`
domain := split(get_user_email(session, user, directory_user), "@")[1]
`),
}
@ -48,6 +51,7 @@ func (c domainCriterion) GenerateRule(_ string, data parser.Value) (*ast.Rule, [
rules.GetSession(),
rules.GetUser(),
rules.GetUserEmail(),
rules.GetDirectoryUser(),
}, nil
}

View file

@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/pomerium/datasource/pkg/directory"
"github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/grpc/session"
"github.com/pomerium/pomerium/pkg/grpc/user"
@ -66,4 +67,25 @@ allow:
require.Equal(t, A{true, A{ReasonDomainOK}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
t.Run("by directory user", func(t *testing.T) {
res, err := evaluate(t, `
allow:
and:
- domain:
is: example.com
`,
[]*databroker.Record{
makeRecord(&session.Session{
Id: "SESSION_ID",
UserId: "USER_ID",
}),
makeStructRecord(directory.UserRecordType, "USER_ID", map[string]any{
"email": "user@example.com",
}),
},
Input{Session: InputSession{ID: "SESSION_ID"}})
require.NoError(t, err)
require.Equal(t, A{true, A{ReasonDomainOK}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
}

View file

@ -16,7 +16,10 @@ var emailBody = ast.Body{
user := get_user(session)
`),
ast.MustParseExpr(`
email := get_user_email(session, user)
directory_user := get_directory_user(session)
`),
ast.MustParseExpr(`
email := get_user_email(session, user, directory_user)
`),
}
@ -49,6 +52,7 @@ func (c emailCriterion) GenerateRule(_ string, data parser.Value) (*ast.Rule, []
rules.GetSession(),
rules.GetUser(),
rules.GetUserEmail(),
rules.GetDirectoryUser(),
}, nil
}

View file

@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"github.com/pomerium/datasource/pkg/directory"
"github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/grpc/session"
"github.com/pomerium/pomerium/pkg/grpc/user"
@ -76,4 +77,25 @@ allow:
require.Equal(t, A{true, A{ReasonEmailOK}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
t.Run("by directory user", func(t *testing.T) {
res, err := evaluate(t, `
allow:
and:
- email:
is: test@example.com
`,
[]*databroker.Record{
makeRecord(&session.Session{
Id: "SESSION_ID",
UserId: "USER_ID",
}),
makeStructRecord(directory.UserRecordType, "USER_ID", map[string]any{
"email": "test@example.com",
}),
},
Input{Session: InputSession{ID: "SESSION_ID"}})
require.NoError(t, err)
require.Equal(t, A{true, A{ReasonEmailOK}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
}

View file

@ -1,7 +1,11 @@
// Package rules contains useful pre-defined rego AST rules.
package rules
import "github.com/open-policy-agent/opa/ast"
import (
"github.com/open-policy-agent/opa/ast"
"github.com/pomerium/datasource/pkg/directory"
)
// GetSession gets the session for the given id.
func GetSession() *ast.Rule {
@ -24,6 +28,16 @@ get_session(id) := v if {
`)
}
// GetDirectoryUser returns the directory user for the given session.
func GetDirectoryUser() *ast.Rule {
return MustParse(`
get_directory_user(session) := v if {
v = get_databroker_record("` + directory.UserRecordType + `", session.user_id)
v != null
} else := {}
`)
}
// GetUser returns the user for the given session.
func GetUser() *ast.Rule {
return MustParse(`
@ -37,7 +51,10 @@ get_user(session) := v if {
// GetUserEmail gets the user email, either the impersonate email, or the user email.
func GetUserEmail() *ast.Rule {
return MustParse(`
get_user_email(session, user) := v if {
get_user_email(session, user, directory_user) := v if {
v = object.get(directory_user, "email", "")
v != ""
} else := v if {
v = user.email
} else := ""
`)