mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-05 20:32:57 +02:00
authorize: move impersonation into session/service account (#1765)
* move impersonation into session/service account * replace frontend statik * fix data race * move JWT filling to separate function, break up functions * maybe fix data race * fix code climate issue
This commit is contained in:
parent
1466f4e5a0
commit
a6bc9f492f
16 changed files with 328 additions and 162 deletions
|
@ -10,7 +10,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
@ -25,8 +24,6 @@ import (
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/session"
|
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/user"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -180,46 +177,7 @@ func (e *Evaluator) JWTPayload(req *Request) map[string]interface{} {
|
||||||
payload := map[string]interface{}{
|
payload := map[string]interface{}{
|
||||||
"iss": e.authenticateHost,
|
"iss": e.authenticateHost,
|
||||||
}
|
}
|
||||||
if u, err := url.Parse(req.HTTP.URL); err == nil {
|
req.fillJWTPayload(payload)
|
||||||
payload["aud"] = u.Hostname()
|
|
||||||
}
|
|
||||||
if s, ok := req.DataBrokerData.Get("type.googleapis.com/session.Session", req.Session.ID).(*session.Session); ok {
|
|
||||||
payload["jti"] = s.GetId()
|
|
||||||
if tm, err := ptypes.Timestamp(s.GetIdToken().GetExpiresAt()); err == nil {
|
|
||||||
payload["exp"] = tm.Unix()
|
|
||||||
}
|
|
||||||
if tm, err := ptypes.Timestamp(s.GetIdToken().GetIssuedAt()); err == nil {
|
|
||||||
payload["iat"] = tm.Unix()
|
|
||||||
}
|
|
||||||
if u, ok := req.DataBrokerData.Get("type.googleapis.com/user.User", s.GetUserId()).(*user.User); ok {
|
|
||||||
payload["sub"] = u.GetId()
|
|
||||||
payload["user"] = u.GetId()
|
|
||||||
payload["email"] = u.GetEmail()
|
|
||||||
}
|
|
||||||
if du, ok := req.DataBrokerData.Get("type.googleapis.com/directory.User", s.GetUserId()).(*directory.User); ok {
|
|
||||||
if du.GetEmail() != "" {
|
|
||||||
payload["email"] = du.GetEmail()
|
|
||||||
}
|
|
||||||
var groupNames []string
|
|
||||||
for _, groupID := range du.GetGroupIds() {
|
|
||||||
if dg, ok := req.DataBrokerData.Get("type.googleapis.com/directory.Group", groupID).(*directory.Group); ok {
|
|
||||||
groupNames = append(groupNames, dg.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var groups []string
|
|
||||||
groups = append(groups, du.GetGroupIds()...)
|
|
||||||
groups = append(groups, groupNames...)
|
|
||||||
payload["groups"] = groups
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Session.ImpersonateEmail != "" {
|
|
||||||
payload["email"] = req.Session.ImpersonateEmail
|
|
||||||
}
|
|
||||||
if len(req.Session.ImpersonateGroups) > 0 {
|
|
||||||
payload["groups"] = req.Session.ImpersonateGroups
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,10 +263,18 @@ func (e *Evaluator) newInput(req *Request, isValidClientCertificate bool) *input
|
||||||
if i.DataBrokerData.Session == nil {
|
if i.DataBrokerData.Session == nil {
|
||||||
i.DataBrokerData.Session = req.DataBrokerData.Get(serviceAccountTypeURL, req.Session.ID)
|
i.DataBrokerData.Session = req.DataBrokerData.Get(serviceAccountTypeURL, req.Session.ID)
|
||||||
}
|
}
|
||||||
if obj, ok := i.DataBrokerData.Session.(interface{ GetUserId() string }); ok {
|
var userIDs []string
|
||||||
i.DataBrokerData.User = req.DataBrokerData.Get(userTypeURL, obj.GetUserId())
|
if obj, ok := i.DataBrokerData.Session.(interface{ GetUserId() string }); ok && obj.GetUserId() != "" {
|
||||||
|
userIDs = append(userIDs, obj.GetUserId())
|
||||||
|
}
|
||||||
|
if obj, ok := i.DataBrokerData.Session.(interface{ GetImpersonateUserId() string }); ok && obj.GetImpersonateUserId() != "" {
|
||||||
|
userIDs = append(userIDs, obj.GetImpersonateUserId())
|
||||||
|
}
|
||||||
|
|
||||||
user, ok := req.DataBrokerData.Get(directoryUserTypeURL, obj.GetUserId()).(*directory.User)
|
for _, userID := range userIDs {
|
||||||
|
i.DataBrokerData.User = req.DataBrokerData.Get(userTypeURL, userID)
|
||||||
|
|
||||||
|
user, ok := req.DataBrokerData.Get(directoryUserTypeURL, userID).(*directory.User)
|
||||||
if ok {
|
if ok {
|
||||||
var groups []string
|
var groups []string
|
||||||
for _, groupID := range user.GetGroupIds() {
|
for _, groupID := range user.GetGroupIds() {
|
||||||
|
@ -331,31 +297,6 @@ func (e *Evaluator) newInput(req *Request, isValidClientCertificate bool) *input
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
|
||||||
// Request is the request data used for the evaluator.
|
|
||||||
Request struct {
|
|
||||||
DataBrokerData DataBrokerData `json:"databroker_data"`
|
|
||||||
HTTP RequestHTTP `json:"http"`
|
|
||||||
Session RequestSession `json:"session"`
|
|
||||||
CustomPolicies []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestHTTP is the HTTP field in the request.
|
|
||||||
RequestHTTP struct {
|
|
||||||
Method string `json:"method"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Headers map[string]string `json:"headers"`
|
|
||||||
ClientCertificate string `json:"client_certificate"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestSession is the session field in the request.
|
|
||||||
RequestSession struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
ImpersonateEmail string `json:"impersonate_email"`
|
|
||||||
ImpersonateGroups []string `json:"impersonate_groups"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Result is the result of evaluation.
|
// Result is the result of evaluation.
|
||||||
type Result struct {
|
type Result struct {
|
||||||
Status int
|
Status int
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
"gopkg.in/square/go-jose.v2/jwt"
|
"gopkg.in/square/go-jose.v2/jwt"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
|
@ -58,9 +59,7 @@ func TestJSONMarshal(t *testing.T) {
|
||||||
ClientCertificate: "CLIENT_CERTIFICATE",
|
ClientCertificate: "CLIENT_CERTIFICATE",
|
||||||
},
|
},
|
||||||
Session: RequestSession{
|
Session: RequestSession{
|
||||||
ID: "SESSION_ID",
|
ID: "SESSION_ID",
|
||||||
ImpersonateEmail: "y@example.com",
|
|
||||||
ImpersonateGroups: []string{"group1"},
|
|
||||||
},
|
},
|
||||||
}, true))
|
}, true))
|
||||||
assert.JSONEq(t, `{
|
assert.JSONEq(t, `{
|
||||||
|
@ -79,9 +78,7 @@ func TestJSONMarshal(t *testing.T) {
|
||||||
"url": "https://example.com"
|
"url": "https://example.com"
|
||||||
},
|
},
|
||||||
"session": {
|
"session": {
|
||||||
"id": "SESSION_ID",
|
"id": "SESSION_ID"
|
||||||
"impersonate_email": "y@example.com",
|
|
||||||
"impersonate_groups": ["group1"]
|
|
||||||
},
|
},
|
||||||
"is_valid_client_certificate": true
|
"is_valid_client_certificate": true
|
||||||
}`, string(bs))
|
}`, string(bs))
|
||||||
|
@ -158,6 +155,7 @@ func TestEvaluator_JWTPayload(t *testing.T) {
|
||||||
ExpiresAt: nowPb,
|
ExpiresAt: nowPb,
|
||||||
IssuedAt: nowPb,
|
IssuedAt: nowPb,
|
||||||
},
|
},
|
||||||
|
ExpiresAt: nowPb,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -174,6 +172,31 @@ func TestEvaluator_JWTPayload(t *testing.T) {
|
||||||
"iat": now.Unix(),
|
"iat": now.Unix(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"with service account",
|
||||||
|
&Request{
|
||||||
|
DataBrokerData: DataBrokerData{
|
||||||
|
"type.googleapis.com/user.ServiceAccount": map[string]interface{}{
|
||||||
|
"SERVICE_ACCOUNT_ID": &user.ServiceAccount{
|
||||||
|
Id: "SERVICE_ACCOUNT_ID",
|
||||||
|
IssuedAt: nowPb,
|
||||||
|
ExpiresAt: nowPb,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HTTP: RequestHTTP{URL: "https://example.com"},
|
||||||
|
Session: RequestSession{
|
||||||
|
ID: "SERVICE_ACCOUNT_ID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"iss": "authn.example.com",
|
||||||
|
"jti": "SERVICE_ACCOUNT_ID",
|
||||||
|
"aud": "example.com",
|
||||||
|
"exp": now.Unix(),
|
||||||
|
"iat": now.Unix(),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"with user",
|
"with user",
|
||||||
&Request{
|
&Request{
|
||||||
|
@ -252,12 +275,22 @@ func TestEvaluator_JWTPayload(t *testing.T) {
|
||||||
&Request{
|
&Request{
|
||||||
HTTP: RequestHTTP{URL: "https://example.com"},
|
HTTP: RequestHTTP{URL: "https://example.com"},
|
||||||
Session: RequestSession{
|
Session: RequestSession{
|
||||||
ImpersonateEmail: "user@example.com",
|
ID: "SESSION_ID",
|
||||||
ImpersonateGroups: []string{"admin", "test"},
|
},
|
||||||
|
DataBrokerData: DataBrokerData{
|
||||||
|
"type.googleapis.com/session.Session": map[string]interface{}{
|
||||||
|
"SESSION_ID": &session.Session{
|
||||||
|
Id: "SESSION_ID",
|
||||||
|
UserId: "USER_ID",
|
||||||
|
ImpersonateEmail: proto.String("user@example.com"),
|
||||||
|
ImpersonateGroups: []string{"admin", "test"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"iss": "authn.example.com",
|
"iss": "authn.example.com",
|
||||||
|
"jti": "SESSION_ID",
|
||||||
"aud": "example.com",
|
"aud": "example.com",
|
||||||
"email": "user@example.com",
|
"email": "user@example.com",
|
||||||
"groups": []string{"admin", "test"},
|
"groups": []string{"admin", "test"},
|
||||||
|
|
|
@ -14,7 +14,7 @@ all_allowed_groups := get_allowed_groups(route_policy)
|
||||||
all_allowed_users := get_allowed_users(route_policy)
|
all_allowed_users := get_allowed_users(route_policy)
|
||||||
all_allowed_idp_claims := get_allowed_idp_claims(route_policy)
|
all_allowed_idp_claims := get_allowed_idp_claims(route_policy)
|
||||||
|
|
||||||
is_impersonating := count(input.session.impersonate_email) > 0
|
is_impersonating := count(session.impersonate_email) > 0
|
||||||
|
|
||||||
# allow public
|
# allow public
|
||||||
allow {
|
allow {
|
||||||
|
@ -52,14 +52,14 @@ allow {
|
||||||
# allow by impersonate email
|
# allow by impersonate email
|
||||||
allow {
|
allow {
|
||||||
is_impersonating
|
is_impersonating
|
||||||
all_allowed_users[_] = input.session.impersonate_email
|
all_allowed_users[_] = session.impersonate_email
|
||||||
}
|
}
|
||||||
|
|
||||||
# allow by impersonate group
|
# allow by impersonate group
|
||||||
allow {
|
allow {
|
||||||
is_impersonating
|
is_impersonating
|
||||||
some group
|
some group
|
||||||
input.session.impersonate_groups[_] = group
|
session.impersonate_groups[_] = group
|
||||||
all_allowed_groups[_] = group
|
all_allowed_groups[_] = group
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ allow {
|
||||||
allow {
|
allow {
|
||||||
is_impersonating
|
is_impersonating
|
||||||
some domain
|
some domain
|
||||||
email_in_domain(input.session.impersonate_email, all_allowed_domains[domain])
|
email_in_domain(session.impersonate_email, all_allowed_domains[domain])
|
||||||
}
|
}
|
||||||
|
|
||||||
# allow by arbitrary idp claims
|
# allow by arbitrary idp claims
|
||||||
|
|
|
@ -15,7 +15,7 @@ test_email_allowed {
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_impersonate_email_not_allowed {
|
test_impersonate_email_not_allowed {
|
||||||
|
@ -26,14 +26,14 @@ test_impersonate_email_not_allowed {
|
||||||
}] with
|
}] with
|
||||||
input.databroker_data as {
|
input.databroker_data as {
|
||||||
"session": {
|
"session": {
|
||||||
"user_id": "user1"
|
"user_id": "user1", "impersonate_email": "y@example.com"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"email": "x@example.com"
|
"email": "x@example.com"
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "y@example.com" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_impersonate_email_allowed {
|
test_impersonate_email_allowed {
|
||||||
|
@ -44,14 +44,14 @@ test_impersonate_email_allowed {
|
||||||
}] with
|
}] with
|
||||||
input.databroker_data as {
|
input.databroker_data as {
|
||||||
"session": {
|
"session": {
|
||||||
"user_id": "user1"
|
"user_id": "user1", "impersonate_email": "y@example.com"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"email": "x@example.com"
|
"email": "x@example.com"
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "y@example.com" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_group_allowed {
|
test_group_allowed {
|
||||||
|
@ -81,7 +81,7 @@ test_impersonate_groups_not_allowed {
|
||||||
}] with
|
}] with
|
||||||
input.databroker_data as {
|
input.databroker_data as {
|
||||||
"session": {
|
"session": {
|
||||||
"user_id": "user1"
|
"user_id": "user1", "impersonate_email": "y@example.com", "impersonate_groups": ["2"]
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"email": "x@example.com"
|
"email": "x@example.com"
|
||||||
|
@ -89,7 +89,7 @@ test_impersonate_groups_not_allowed {
|
||||||
"groups": ["1"]
|
"groups": ["1"]
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "y@example.com", "impersonate_groups": ["2"] }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_impersonate_groups_allowed {
|
test_impersonate_groups_allowed {
|
||||||
|
@ -100,7 +100,7 @@ test_impersonate_groups_allowed {
|
||||||
}] with
|
}] with
|
||||||
input.databroker_data as {
|
input.databroker_data as {
|
||||||
"session": {
|
"session": {
|
||||||
"user_id": "user1"
|
"user_id": "user1", "impersonate_email": "y@example.com", "impersonate_groups": ["2"]
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"email": "x@example.com"
|
"email": "x@example.com"
|
||||||
|
@ -110,7 +110,7 @@ test_impersonate_groups_allowed {
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "y@example.com", "impersonate_groups": ["2"] }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_domain_allowed {
|
test_domain_allowed {
|
||||||
|
@ -121,14 +121,14 @@ test_domain_allowed {
|
||||||
}] with
|
}] with
|
||||||
input.databroker_data as {
|
input.databroker_data as {
|
||||||
"session": {
|
"session": {
|
||||||
"user_id": "user1"
|
"user_id": "user1", "impersonate_email": ""
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"email": "x@example.com"
|
"email": "x@example.com"
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_impersonate_domain_not_allowed {
|
test_impersonate_domain_not_allowed {
|
||||||
|
@ -139,14 +139,14 @@ test_impersonate_domain_not_allowed {
|
||||||
}] with
|
}] with
|
||||||
input.databroker_data as {
|
input.databroker_data as {
|
||||||
"session": {
|
"session": {
|
||||||
"user_id": "user1"
|
"user_id": "user1", "impersonate_email": "y@example1.com"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"email": "x@example.com"
|
"email": "x@example.com"
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "y@example1.com" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_impersonate_domain_allowed {
|
test_impersonate_domain_allowed {
|
||||||
|
@ -157,14 +157,14 @@ test_impersonate_domain_allowed {
|
||||||
}] with
|
}] with
|
||||||
input.databroker_data as {
|
input.databroker_data as {
|
||||||
"session": {
|
"session": {
|
||||||
"user_id": "user1"
|
"user_id": "user1", "impersonate_email": "y@example1.com"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"email": "x@example.com"
|
"email": "x@example.com"
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "y@example1.com" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_idp_claims_allowed {
|
test_idp_claims_allowed {
|
||||||
|
@ -183,7 +183,7 @@ test_idp_claims_allowed {
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
test_example {
|
test_example {
|
||||||
|
@ -395,7 +395,7 @@ test_any_authenticated_user_allowed {
|
||||||
}
|
}
|
||||||
} with
|
} with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
test_any_authenticated_user_denied {
|
test_any_authenticated_user_denied {
|
||||||
not allow with
|
not allow with
|
||||||
|
@ -404,5 +404,5 @@ test_any_authenticated_user_denied {
|
||||||
"AllowAnyAuthenticatedUser": true
|
"AllowAnyAuthenticatedUser": true
|
||||||
}] with
|
}] with
|
||||||
input.http as { "url": "http://example.com" } with
|
input.http as { "url": "http://example.com" } with
|
||||||
input.session as { "id": "session1", "impersonate_email": "" }
|
input.session as { "id": "session1" }
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
100
authorize/evaluator/request.go
Normal file
100
authorize/evaluator/request.go
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package evaluator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/directory"
|
||||||
|
"github.com/pomerium/pomerium/pkg/grpc/session"
|
||||||
|
"github.com/pomerium/pomerium/pkg/grpc/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Request is the request data used for the evaluator.
|
||||||
|
Request struct {
|
||||||
|
DataBrokerData DataBrokerData `json:"databroker_data"`
|
||||||
|
HTTP RequestHTTP `json:"http"`
|
||||||
|
Session RequestSession `json:"session"`
|
||||||
|
CustomPolicies []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestHTTP is the HTTP field in the request.
|
||||||
|
RequestHTTP struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
|
ClientCertificate string `json:"client_certificate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestSession is the session field in the request.
|
||||||
|
RequestSession struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type sessionOrServiceAccount interface {
|
||||||
|
GetId() string
|
||||||
|
GetExpiresAt() *timestamppb.Timestamp
|
||||||
|
GetIssuedAt() *timestamppb.Timestamp
|
||||||
|
GetUserId() string
|
||||||
|
GetImpersonateEmail() string
|
||||||
|
GetImpersonateGroups() []string
|
||||||
|
GetImpersonateUserId() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) fillJWTPayload(payload map[string]interface{}) {
|
||||||
|
if u, err := url.Parse(req.HTTP.URL); err == nil {
|
||||||
|
payload["aud"] = u.Hostname()
|
||||||
|
}
|
||||||
|
|
||||||
|
if s, ok := req.DataBrokerData.Get("type.googleapis.com/session.Session", req.Session.ID).(*session.Session); ok {
|
||||||
|
req.fillJWTPayloadSessionOrServiceAccount(payload, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sa, ok := req.DataBrokerData.Get("type.googleapis.com/user.ServiceAccount", req.Session.ID).(*user.ServiceAccount); ok {
|
||||||
|
req.fillJWTPayloadSessionOrServiceAccount(payload, sa)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) fillJWTPayloadSessionOrServiceAccount(payload map[string]interface{}, s sessionOrServiceAccount) {
|
||||||
|
payload["jti"] = s.GetId()
|
||||||
|
if s.GetExpiresAt().IsValid() {
|
||||||
|
payload["exp"] = s.GetExpiresAt().AsTime().Unix()
|
||||||
|
}
|
||||||
|
if s.GetIssuedAt().IsValid() {
|
||||||
|
payload["iat"] = s.GetIssuedAt().AsTime().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := s.GetUserId()
|
||||||
|
if s.GetImpersonateUserId() != "" {
|
||||||
|
userID = s.GetImpersonateUserId()
|
||||||
|
}
|
||||||
|
if u, ok := req.DataBrokerData.Get("type.googleapis.com/user.User", userID).(*user.User); ok {
|
||||||
|
payload["sub"] = u.GetId()
|
||||||
|
payload["user"] = u.GetId()
|
||||||
|
payload["email"] = u.GetEmail()
|
||||||
|
}
|
||||||
|
if du, ok := req.DataBrokerData.Get("type.googleapis.com/directory.User", userID).(*directory.User); ok {
|
||||||
|
if du.GetEmail() != "" {
|
||||||
|
payload["email"] = du.GetEmail()
|
||||||
|
}
|
||||||
|
var groupNames []string
|
||||||
|
for _, groupID := range du.GetGroupIds() {
|
||||||
|
if dg, ok := req.DataBrokerData.Get("type.googleapis.com/directory.Group", groupID).(*directory.Group); ok {
|
||||||
|
groupNames = append(groupNames, dg.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var groups []string
|
||||||
|
groups = append(groups, du.GetGroupIds()...)
|
||||||
|
groups = append(groups, groupNames...)
|
||||||
|
payload["groups"] = groups
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.GetImpersonateEmail() != "" {
|
||||||
|
payload["email"] = s.GetImpersonateEmail()
|
||||||
|
}
|
||||||
|
if len(s.GetImpersonateGroups()) > 0 {
|
||||||
|
payload["groups"] = s.GetImpersonateGroups()
|
||||||
|
}
|
||||||
|
}
|
|
@ -230,9 +230,7 @@ func (a *Authorize) getEvaluatorRequestFromCheckRequest(in *envoy_service_auth_v
|
||||||
}
|
}
|
||||||
if sessionState != nil {
|
if sessionState != nil {
|
||||||
req.Session = evaluator.RequestSession{
|
req.Session = evaluator.RequestSession{
|
||||||
ID: sessionState.ID,
|
ID: sessionState.ID,
|
||||||
ImpersonateEmail: sessionState.ImpersonateEmail,
|
|
||||||
ImpersonateGroups: sessionState.ImpersonateGroups,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p := a.getMatchingPolicy(requestURL)
|
p := a.getMatchingPolicy(requestURL)
|
||||||
|
|
|
@ -92,9 +92,7 @@ func Test_getEvaluatorRequest(t *testing.T) {
|
||||||
)
|
)
|
||||||
expect := &evaluator.Request{
|
expect := &evaluator.Request{
|
||||||
Session: evaluator.RequestSession{
|
Session: evaluator.RequestSession{
|
||||||
ID: "SESSION_ID",
|
ID: "SESSION_ID",
|
||||||
ImpersonateEmail: "foo@example.com",
|
|
||||||
ImpersonateGroups: []string{"admin", "test"},
|
|
||||||
},
|
},
|
||||||
HTTP: evaluator.RequestHTTP{
|
HTTP: evaluator.RequestHTTP{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
|
|
|
@ -22,14 +22,12 @@ import (
|
||||||
var (
|
var (
|
||||||
errObtainCertFailed = errors.New("obtain cert failed")
|
errObtainCertFailed = errors.New("obtain cert failed")
|
||||||
errRenewCertFailed = errors.New("renew cert failed")
|
errRenewCertFailed = errors.New("renew cert failed")
|
||||||
|
|
||||||
checkInterval = time.Minute * 10
|
|
||||||
acmeTemplate = certmagic.DefaultACME
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Manager manages TLS certificates.
|
// Manager manages TLS certificates.
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
src config.Source
|
src config.Source
|
||||||
|
acmeTemplate certmagic.ACMEManager
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
config *config.Config
|
config *config.Config
|
||||||
|
@ -42,6 +40,14 @@ type Manager struct {
|
||||||
|
|
||||||
// New creates a new autocert manager.
|
// New creates a new autocert manager.
|
||||||
func New(src config.Source) (*Manager, error) {
|
func New(src config.Source) (*Manager, error) {
|
||||||
|
return newManager(context.Background(), src, certmagic.DefaultACME, time.Minute*10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newManager(ctx context.Context,
|
||||||
|
src config.Source,
|
||||||
|
acmeTemplate certmagic.ACMEManager,
|
||||||
|
checkInterval time.Duration,
|
||||||
|
) (*Manager, error) {
|
||||||
// set certmagic default storage cache, otherwise cert renewal loop will be based off
|
// set certmagic default storage cache, otherwise cert renewal loop will be based off
|
||||||
// certmagic's own default location
|
// certmagic's own default location
|
||||||
certmagic.Default.Storage = &certmagic.FileStorage{
|
certmagic.Default.Storage = &certmagic.FileStorage{
|
||||||
|
@ -50,8 +56,9 @@ func New(src config.Source) (*Manager, error) {
|
||||||
certmagic.Default.Logger = log.ZapLogger().With(zap.String("service", "autocert"))
|
certmagic.Default.Logger = log.ZapLogger().With(zap.String("service", "autocert"))
|
||||||
|
|
||||||
mgr := &Manager{
|
mgr := &Manager{
|
||||||
src: src,
|
src: src,
|
||||||
certmagic: certmagic.NewDefault(),
|
acmeTemplate: acmeTemplate,
|
||||||
|
certmagic: certmagic.NewDefault(),
|
||||||
}
|
}
|
||||||
err := mgr.update(src.GetConfig())
|
err := mgr.update(src.GetConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -71,11 +78,16 @@ func New(src config.Source) (*Manager, error) {
|
||||||
ticker := time.NewTicker(checkInterval)
|
ticker := time.NewTicker(checkInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for range ticker.C {
|
for {
|
||||||
err := mgr.renewConfigCerts()
|
select {
|
||||||
if err != nil {
|
case <-ctx.Done():
|
||||||
log.Error().Err(err).Msg("autocert: error updating config")
|
|
||||||
return
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
err := mgr.renewConfigCerts()
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("autocert: error updating config")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -92,7 +104,7 @@ func (mgr *Manager) getCertMagicConfig(options *config.Options) (*certmagic.Conf
|
||||||
return nil, fmt.Errorf("config: failed caching cert: %w", err)
|
return nil, fmt.Errorf("config: failed caching cert: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
acmeMgr := certmagic.NewACMEManager(mgr.certmagic, acmeTemplate)
|
acmeMgr := certmagic.NewACMEManager(mgr.certmagic, mgr.acmeTemplate)
|
||||||
acmeMgr.Agreed = true
|
acmeMgr.Agreed = true
|
||||||
if options.AutocertOptions.UseStaging {
|
if options.AutocertOptions.UseStaging {
|
||||||
acmeMgr.CA = acmeMgr.TestCA
|
acmeMgr.CA = acmeMgr.TestCA
|
||||||
|
|
|
@ -2,6 +2,7 @@ package autocert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
@ -122,6 +123,9 @@ func newMockACME(srv *httptest.Server) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfig(t *testing.T) {
|
func TestConfig(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
var mockACME http.Handler
|
var mockACME http.Handler
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
mockACME.ServeHTTP(w, r)
|
mockACME.ServeHTTP(w, r)
|
||||||
|
@ -140,23 +144,12 @@ func TestConfig(t *testing.T) {
|
||||||
addr := li.Addr().String()
|
addr := li.Addr().String()
|
||||||
_ = li.Close()
|
_ = li.Close()
|
||||||
|
|
||||||
oAcmeTemplate := acmeTemplate
|
|
||||||
defer func() { acmeTemplate = oAcmeTemplate }()
|
|
||||||
acmeTemplate = certmagic.ACMEManager{
|
|
||||||
CA: srv.URL + "/acme/directory",
|
|
||||||
TestCA: srv.URL + "/acme/directory",
|
|
||||||
}
|
|
||||||
|
|
||||||
oCheckInterval := checkInterval
|
|
||||||
defer func() { checkInterval = oCheckInterval }()
|
|
||||||
checkInterval = time.Second
|
|
||||||
|
|
||||||
p1 := config.Policy{
|
p1 := config.Policy{
|
||||||
From: "http://from.example.com", To: "http://to.example.com",
|
From: "http://from.example.com", To: "http://to.example.com",
|
||||||
}
|
}
|
||||||
_ = p1.Validate()
|
_ = p1.Validate()
|
||||||
|
|
||||||
mgr, err := New(config.NewStaticSource(&config.Config{
|
mgr, err := newManager(ctx, config.NewStaticSource(&config.Config{
|
||||||
Options: &config.Options{
|
Options: &config.Options{
|
||||||
AutocertOptions: config.AutocertOptions{
|
AutocertOptions: config.AutocertOptions{
|
||||||
Enable: true,
|
Enable: true,
|
||||||
|
@ -167,7 +160,10 @@ func TestConfig(t *testing.T) {
|
||||||
HTTPRedirectAddr: addr,
|
HTTPRedirectAddr: addr,
|
||||||
Policies: []config.Policy{p1},
|
Policies: []config.Policy{p1},
|
||||||
},
|
},
|
||||||
}))
|
}), certmagic.ACMEManager{
|
||||||
|
CA: srv.URL + "/acme/directory",
|
||||||
|
TestCA: srv.URL + "/acme/directory",
|
||||||
|
}, time.Second)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/golang/protobuf/ptypes"
|
"github.com/golang/protobuf/ptypes"
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/internal/identity"
|
"github.com/pomerium/pomerium/internal/identity"
|
||||||
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
||||||
|
@ -71,3 +72,8 @@ func (x *Session) SetRawIDToken(rawIDToken string) {
|
||||||
}
|
}
|
||||||
x.IdToken.Raw = rawIDToken
|
x.IdToken.Raw = rawIDToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetIssuedAt returns the issued at timestamp for the id token.
|
||||||
|
func (x *Session) GetIssuedAt() *timestamppb.Timestamp {
|
||||||
|
return x.GetIdToken().GetIssuedAt()
|
||||||
|
}
|
||||||
|
|
|
@ -182,14 +182,17 @@ type Session struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
|
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
|
||||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
UserId string `protobuf:"bytes,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
UserId string `protobuf:"bytes,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||||
ExpiresAt *timestamp.Timestamp `protobuf:"bytes,4,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
|
ExpiresAt *timestamp.Timestamp `protobuf:"bytes,4,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
|
||||||
IdToken *IDToken `protobuf:"bytes,6,opt,name=id_token,json=idToken,proto3" json:"id_token,omitempty"`
|
IdToken *IDToken `protobuf:"bytes,6,opt,name=id_token,json=idToken,proto3" json:"id_token,omitempty"`
|
||||||
OauthToken *OAuthToken `protobuf:"bytes,7,opt,name=oauth_token,json=oauthToken,proto3" json:"oauth_token,omitempty"`
|
OauthToken *OAuthToken `protobuf:"bytes,7,opt,name=oauth_token,json=oauthToken,proto3" json:"oauth_token,omitempty"`
|
||||||
Claims map[string]*_struct.ListValue `protobuf:"bytes,9,rep,name=claims,proto3" json:"claims,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Claims map[string]*_struct.ListValue `protobuf:"bytes,9,rep,name=claims,proto3" json:"claims,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
Audience []string `protobuf:"bytes,10,rep,name=audience,proto3" json:"audience,omitempty"`
|
Audience []string `protobuf:"bytes,10,rep,name=audience,proto3" json:"audience,omitempty"`
|
||||||
|
ImpersonateUserId *string `protobuf:"bytes,11,opt,name=impersonate_user_id,json=impersonateUserId,proto3,oneof" json:"impersonate_user_id,omitempty"`
|
||||||
|
ImpersonateEmail *string `protobuf:"bytes,12,opt,name=impersonate_email,json=impersonateEmail,proto3,oneof" json:"impersonate_email,omitempty"`
|
||||||
|
ImpersonateGroups []string `protobuf:"bytes,13,rep,name=impersonate_groups,json=impersonateGroups,proto3" json:"impersonate_groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Session) Reset() {
|
func (x *Session) Reset() {
|
||||||
|
@ -280,6 +283,27 @@ func (x *Session) GetAudience() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Session) GetImpersonateUserId() string {
|
||||||
|
if x != nil && x.ImpersonateUserId != nil {
|
||||||
|
return *x.ImpersonateUserId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Session) GetImpersonateEmail() string {
|
||||||
|
if x != nil && x.ImpersonateEmail != nil {
|
||||||
|
return *x.ImpersonateEmail
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Session) GetImpersonateGroups() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ImpersonateGroups
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var File_session_proto protoreflect.FileDescriptor
|
var File_session_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_session_proto_rawDesc = []byte{
|
var file_session_proto_rawDesc = []byte{
|
||||||
|
@ -311,7 +335,7 @@ var file_session_proto_rawDesc = []byte{
|
||||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78,
|
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78,
|
||||||
0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65,
|
0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65,
|
||||||
0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
||||||
0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x93, 0x03, 0x0a,
|
0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xd7, 0x04, 0x0a,
|
||||||
0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
|
0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
|
||||||
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
|
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
|
||||||
0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
|
0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
|
||||||
|
@ -331,16 +355,28 @@ var file_session_proto_rawDesc = []byte{
|
||||||
0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6c, 0x61, 0x69,
|
0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6c, 0x61, 0x69,
|
||||||
0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x12,
|
0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x12,
|
||||||
0x1a, 0x0a, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x03, 0x28,
|
0x1a, 0x0a, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x03, 0x28,
|
||||||
0x09, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x1a, 0x55, 0x0a, 0x0b, 0x43,
|
0x09, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x13, 0x69,
|
||||||
0x6c, 0x61, 0x69, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f,
|
||||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05,
|
0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x69, 0x6d, 0x70, 0x65,
|
||||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x88, 0x01, 0x01,
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69,
|
0x12, 0x30, 0x0a, 0x11, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f,
|
||||||
0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
|
0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x10, 0x69,
|
||||||
0x38, 0x01, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x88,
|
||||||
0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69,
|
0x01, 0x01, 0x12, 0x2d, 0x0a, 0x12, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74,
|
||||||
0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x65, 0x73, 0x73,
|
0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11,
|
||||||
0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70,
|
||||||
|
0x73, 0x1a, 0x55, 0x0a, 0x0b, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||||
|
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
||||||
|
0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
|
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
|
||||||
|
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x6d, 0x70,
|
||||||
|
0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||||
|
0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65,
|
||||||
|
0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||||
|
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f,
|
||||||
|
0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -423,6 +459,7 @@ func file_session_proto_init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_session_proto_msgTypes[2].OneofWrappers = []interface{}{}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|
|
@ -30,4 +30,8 @@ message Session {
|
||||||
OAuthToken oauth_token = 7;
|
OAuthToken oauth_token = 7;
|
||||||
map<string, google.protobuf.ListValue> claims = 9;
|
map<string, google.protobuf.ListValue> claims = 9;
|
||||||
repeated string audience = 10;
|
repeated string audience = 10;
|
||||||
|
|
||||||
|
optional string impersonate_user_id = 11;
|
||||||
|
optional string impersonate_email = 12;
|
||||||
|
repeated string impersonate_groups = 13;
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,10 +166,13 @@ type ServiceAccount struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||||
ExpiresAt *timestamp.Timestamp `protobuf:"bytes,3,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
|
ExpiresAt *timestamp.Timestamp `protobuf:"bytes,3,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
|
||||||
IssuedAt *timestamp.Timestamp `protobuf:"bytes,4,opt,name=issued_at,json=issuedAt,proto3" json:"issued_at,omitempty"`
|
IssuedAt *timestamp.Timestamp `protobuf:"bytes,4,opt,name=issued_at,json=issuedAt,proto3" json:"issued_at,omitempty"`
|
||||||
|
ImpersonateUserId *string `protobuf:"bytes,5,opt,name=impersonate_user_id,json=impersonateUserId,proto3,oneof" json:"impersonate_user_id,omitempty"`
|
||||||
|
ImpersonateEmail *string `protobuf:"bytes,6,opt,name=impersonate_email,json=impersonateEmail,proto3,oneof" json:"impersonate_email,omitempty"`
|
||||||
|
ImpersonateGroups []string `protobuf:"bytes,7,rep,name=impersonate_groups,json=impersonateGroups,proto3" json:"impersonate_groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ServiceAccount) Reset() {
|
func (x *ServiceAccount) Reset() {
|
||||||
|
@ -232,6 +235,27 @@ func (x *ServiceAccount) GetIssuedAt() *timestamp.Timestamp {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ServiceAccount) GetImpersonateUserId() string {
|
||||||
|
if x != nil && x.ImpersonateUserId != nil {
|
||||||
|
return *x.ImpersonateUserId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServiceAccount) GetImpersonateEmail() string {
|
||||||
|
if x != nil && x.ImpersonateEmail != nil {
|
||||||
|
return *x.ImpersonateEmail
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServiceAccount) GetImpersonateGroups() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ImpersonateGroups
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var File_user_proto protoreflect.FileDescriptor
|
var File_user_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_user_proto_rawDesc = []byte{
|
var file_user_proto_rawDesc = []byte{
|
||||||
|
@ -257,7 +281,7 @@ var file_user_proto_rawDesc = []byte{
|
||||||
0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
|
0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xad, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x72,
|
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf1, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x72,
|
||||||
0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75,
|
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75,
|
||||||
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73,
|
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73,
|
||||||
|
@ -268,10 +292,23 @@ var file_user_proto_rawDesc = []byte{
|
||||||
0x37, 0x0a, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01,
|
0x37, 0x0a, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08,
|
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08,
|
||||||
0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68,
|
0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x12, 0x33, 0x0a, 0x13, 0x69, 0x6d, 0x70, 0x65,
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f,
|
0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
||||||
0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70,
|
0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f,
|
||||||
0x63, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6e, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a,
|
||||||
|
0x11, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6d, 0x61,
|
||||||
|
0x69, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x10, 0x69, 0x6d, 0x70, 0x65,
|
||||||
|
0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x88, 0x01, 0x01, 0x12,
|
||||||
|
0x2d, 0x0a, 0x12, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x67,
|
||||||
|
0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x69, 0x6d, 0x70,
|
||||||
|
0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x42, 0x16,
|
||||||
|
0x0a, 0x14, 0x5f, 0x69, 0x6d, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x75,
|
||||||
|
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x6d, 0x70, 0x65, 0x72,
|
||||||
|
0x73, 0x6f, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x2c, 0x5a, 0x2a,
|
||||||
|
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67,
|
||||||
|
0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -350,6 +387,7 @@ func file_user_proto_init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_user_proto_msgTypes[2].OneofWrappers = []interface{}{}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
|
|
|
@ -24,4 +24,8 @@ message ServiceAccount {
|
||||||
string user_id = 2;
|
string user_id = 2;
|
||||||
google.protobuf.Timestamp expires_at = 3;
|
google.protobuf.Timestamp expires_at = 3;
|
||||||
google.protobuf.Timestamp issued_at = 4;
|
google.protobuf.Timestamp issued_at = 4;
|
||||||
|
|
||||||
|
optional string impersonate_user_id = 5;
|
||||||
|
optional string impersonate_email = 6;
|
||||||
|
repeated string impersonate_groups = 7;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,8 @@ func TestSignedJWT(t *testing.T) {
|
||||||
grpc.StreamInterceptor(StreamRequireSignedJWT(base64.StdEncoding.EncodeToString(key))),
|
grpc.StreamInterceptor(StreamRequireSignedJWT(base64.StdEncoding.EncodeToString(key))),
|
||||||
grpc.UnaryInterceptor(UnaryRequireSignedJWT(base64.StdEncoding.EncodeToString(key))),
|
grpc.UnaryInterceptor(UnaryRequireSignedJWT(base64.StdEncoding.EncodeToString(key))),
|
||||||
)
|
)
|
||||||
go srv.Serve(li)
|
|
||||||
|
|
||||||
reflection.Register(srv)
|
reflection.Register(srv)
|
||||||
|
go srv.Serve(li)
|
||||||
|
|
||||||
t.Run("unauthenticated", func(t *testing.T) {
|
t.Run("unauthenticated", func(t *testing.T) {
|
||||||
cc, err := grpc.Dial(li.Addr().String(),
|
cc, err := grpc.Dial(li.Addr().String(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue