mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:47:33 +00:00
feat: Login, OP Support and Auth Queries (#177)
* fix: change oidc config * fix: change oidc config secret * begin models * begin repo * fix: implement grpc app funcs * fix: add application requests * fix: converter * fix: converter * fix: converter and generate clientid * fix: tests * feat: project grant aggregate * feat: project grant * fix: project grant check if role existing * fix: project grant requests * fix: project grant fixes * fix: project grant member model * fix: project grant member aggregate * fix: project grant member eventstore * fix: project grant member requests * feat: user model * begin repo * repo models and more * feat: user command side * lots of functions * user command side * profile requests * commit before rebase on user * save * local config with gopass and more * begin new auth command (user centric) * Update internal/user/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/user_test.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/eventstore_mock_test.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * changes from mr review * save files into basedir * changes from mr review * changes from mr review * move to auth request * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * changes requested on mr * fix generate codes * fix return if no events * password code * email verification step * more steps * lot of mfa * begin tests * more next steps * auth api * auth api (user) * auth api (user) * auth api (user) * differ requests * merge * tests * fix compilation error * mock for id generator * Update internal/user/repository/eventsourcing/model/password.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * requests of mr * check email * begin separation of command and query * otp * change packages * some cleanup and fixes * tests for auth request / next steps * add VerificationLifetimes to config and make it run * tests * fix code challenge validation * cleanup * fix merge * begin view * repackaging tests and configs * fix startup config for auth * add migration * add PromptSelectAccount * fix copy / paste * remove user_agent files * fixes * fix sequences in user_session * token commands * token queries and signout * fix * fix set password test * add token handler and table * handle session init * add session state * add user view test cases * change VerifyMyMfaOTP * some fixes * fix user repo in auth api * cleanup * add user session view test * fix merge * begin oidc * user agent and more * config * keys * key command and query * add login statics * key handler * start login * login handlers * lot of fixes * merge oidc * add missing exports * add missing exports * fix some bugs * authrequestid in htmls * getrequest * update auth request * fix userid check * add username to authrequest * fix user session and auth request handling * fix UserSessionsByAgentID * fix auth request tests * fix user session on UserPasswordChanged and MfaOtpRemoved * fix MfaTypesSetupPossible * handle mfa * fill username * auth request query checks new events * fix userSessionByIDs * fix tokens * fix userSessionByIDs test * add user selection * init code * user code creation date * add init user step * add verification failed types * add verification failures * verify init code * user init code handle * user init code handle * fix userSessionByIDs * update logging * user agent cookie * browserinfo from request * add DeleteAuthRequest * add static login files to binary * add login statik to build * move generate to separate file and remove statik.go files * remove static dirs from startup.yaml * generate into separate namespaces * merge master * auth request code * auth request type mapping * fix keys * improve tokens * improve register and basic styling * fix ailerons font * improve password reset * add audience to token * all oidc apps as audience * fix test nextStep * fix email texts * remove "not set" * lot of style changes * improve copy to clipboard * fix footer * add cookie handler * remove placeholders * fix compilation after merge * fix auth config * remove comments * typo * use new secrets store * change default pws to match default policy * fixes * add todo * enable login * fix db name * Auth queries (#179) * my usersession * org structure/ auth handlers * working user grant spooler * auth internal user grants * search my project orgs * remove permissions file * my zitadel permissions * my zitadel permissions * remove unused code * authz * app searches in view * token verification * fix user grant load * fix tests * fix tests * read configs * remove unused const * remove todos * env variables * app_name * working authz * search projects * global resourceowner * Update internal/api/auth/permissions.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/api/auth/permissions.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * model2 rename * at least it works * check token expiry * search my user grants * remove token table from authz Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix test * fix ports and enable console Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
|
||||
"github.com/caos/logging"
|
||||
@@ -15,9 +16,9 @@ type Config struct {
|
||||
API api.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
||||
func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
||||
repo, err := eventsourcing.Start(ctx, config.Repository, systemDefaults)
|
||||
logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app")
|
||||
|
||||
api.Start(ctx, config.API, authZ, repo)
|
||||
api.Start(ctx, config.API, authZRepo, authZ, repo)
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
|
||||
"github.com/caos/zitadel/internal/admin/repository"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
@@ -14,8 +15,8 @@ type Config struct {
|
||||
GRPC grpc_util.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, conf Config, authZ auth.Config, repo repository.Repository) {
|
||||
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo)
|
||||
func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) {
|
||||
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, repo)
|
||||
grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig())
|
||||
|
||||
server.StartServer(ctx, grpcServer)
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
||||
"github.com/caos/zitadel/internal/api/grpc/server/middleware"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
@@ -20,13 +21,13 @@ type Server struct {
|
||||
repo repository.Repository
|
||||
}
|
||||
|
||||
func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository.Repository) *Server {
|
||||
func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server {
|
||||
return &Server{
|
||||
port: conf.Port,
|
||||
org: repo,
|
||||
repo: repo,
|
||||
authZ: authZ,
|
||||
verifier: admin_auth.Start(),
|
||||
verifier: admin_auth.Start(authZRepo),
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,22 +2,29 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
|
||||
auth_util "github.com/caos/zitadel/internal/api/auth"
|
||||
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
||||
"github.com/caos/zitadel/internal/api/grpc/server"
|
||||
"github.com/caos/zitadel/internal/auth/repository"
|
||||
"github.com/caos/zitadel/pkg/auth/api/grpc"
|
||||
"github.com/caos/zitadel/pkg/auth/api/oidc"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
GRPC grpc_util.Config
|
||||
OIDC oidc.OPHandlerConfig
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, conf Config, authZ auth_util.Config, repo repository.Repository) {
|
||||
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo)
|
||||
func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth_util.Config, authRepo repository.Repository) {
|
||||
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, authRepo)
|
||||
grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig())
|
||||
oidcHandler := oidc.NewProvider(ctx, conf.OIDC, authRepo)
|
||||
|
||||
server.StartServer(ctx, grpcServer)
|
||||
server.StartGateway(ctx, grpcGateway)
|
||||
op.Start(ctx, oidcHandler)
|
||||
}
|
||||
|
@@ -105,12 +105,12 @@ var AuthService_AuthMethods = utils_auth.MethodMapping{
|
||||
CheckParam: "",
|
||||
},
|
||||
|
||||
"/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs": utils_auth.Option{
|
||||
"/zitadel.auth.api.v1.AuthService/SearchMyUserGrant": utils_auth.Option{
|
||||
Permission: "authenticated",
|
||||
CheckParam: "",
|
||||
},
|
||||
|
||||
"/zitadel.auth.api.v1.AuthService/IsIamAdmin": utils_auth.Option{
|
||||
"/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs": utils_auth.Option{
|
||||
Permission: "authenticated",
|
||||
CheckParam: "",
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -19,22 +19,6 @@
|
||||
"application/grpc"
|
||||
],
|
||||
"paths": {
|
||||
"/global/_isiamadmin": {
|
||||
"get": {
|
||||
"operationId": "IsIamAdmin",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1IsAdminResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"AuthService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/global/projectorgs/_search": {
|
||||
"post": {
|
||||
"operationId": "SearchMyProjectOrgs",
|
||||
@@ -128,6 +112,32 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/usergrants/me/_search": {
|
||||
"post": {
|
||||
"operationId": "SearchMyUserGrant",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1UserGrantSearchResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1UserGrantSearchRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"AuthService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/me/address": {
|
||||
"get": {
|
||||
"operationId": "GetMyUserAddress",
|
||||
@@ -510,7 +520,7 @@
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"type": "object"
|
||||
"$ref": "#/definitions/protobufStruct"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -521,6 +531,19 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"protobufListValue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/protobufValue"
|
||||
},
|
||||
"description": "Repeated field of dynamically typed values."
|
||||
}
|
||||
},
|
||||
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
|
||||
},
|
||||
"protobufNullValue": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -529,6 +552,51 @@
|
||||
"default": "NULL_VALUE",
|
||||
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
|
||||
},
|
||||
"protobufStruct": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fields": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/protobufValue"
|
||||
},
|
||||
"description": "Unordered map of dynamically typed values."
|
||||
}
|
||||
},
|
||||
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
|
||||
},
|
||||
"protobufValue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"null_value": {
|
||||
"$ref": "#/definitions/protobufNullValue",
|
||||
"description": "Represents a null value."
|
||||
},
|
||||
"number_value": {
|
||||
"type": "number",
|
||||
"format": "double",
|
||||
"description": "Represents a double value."
|
||||
},
|
||||
"string_value": {
|
||||
"type": "string",
|
||||
"description": "Represents a string value."
|
||||
},
|
||||
"bool_value": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
"description": "Represents a boolean value."
|
||||
},
|
||||
"struct_value": {
|
||||
"$ref": "#/definitions/protobufStruct",
|
||||
"description": "Represents a structured value."
|
||||
},
|
||||
"list_value": {
|
||||
"$ref": "#/definitions/protobufListValue",
|
||||
"description": "Represents a repeated `Value`."
|
||||
}
|
||||
},
|
||||
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
|
||||
},
|
||||
"v1Gender": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -539,15 +607,6 @@
|
||||
],
|
||||
"default": "GENDER_UNSPECIFIED"
|
||||
},
|
||||
"v1IsAdminResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"is_admin": {
|
||||
"type": "boolean",
|
||||
"format": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1MFAState": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -712,7 +771,10 @@
|
||||
"enum": [
|
||||
"SEARCHMETHOD_EQUALS",
|
||||
"SEARCHMETHOD_STARTS_WITH",
|
||||
"SEARCHMETHOD_CONTAINS"
|
||||
"SEARCHMETHOD_CONTAINS",
|
||||
"SEARCHMETHOD_EQUALS_IGNORE_CASE",
|
||||
"SEARCHMETHOD_STARTS_WITH_IGNORE_CASE",
|
||||
"SEARCHMETHOD_CONTAINS_IGNORE_CASE"
|
||||
],
|
||||
"default": "SEARCHMETHOD_EQUALS"
|
||||
},
|
||||
@@ -837,6 +899,101 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1UserGrantSearchKey": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"UserGrantSearchKey_UNKNOWN",
|
||||
"UserGrantSearchKey_ORG_ID",
|
||||
"UserGrantSearchKey_PROJECT_ID"
|
||||
],
|
||||
"default": "UserGrantSearchKey_UNKNOWN"
|
||||
},
|
||||
"v1UserGrantSearchQuery": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"$ref": "#/definitions/v1UserGrantSearchKey"
|
||||
},
|
||||
"method": {
|
||||
"$ref": "#/definitions/v1SearchMethod"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1UserGrantSearchRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"offset": {
|
||||
"type": "string",
|
||||
"format": "uint64"
|
||||
},
|
||||
"limit": {
|
||||
"type": "string",
|
||||
"format": "uint64"
|
||||
},
|
||||
"sorting_column": {
|
||||
"$ref": "#/definitions/v1UserGrantSearchKey"
|
||||
},
|
||||
"asc": {
|
||||
"type": "boolean",
|
||||
"format": "boolean"
|
||||
},
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1UserGrantSearchQuery"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1UserGrantSearchResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"offset": {
|
||||
"type": "string",
|
||||
"format": "uint64"
|
||||
},
|
||||
"limit": {
|
||||
"type": "string",
|
||||
"format": "uint64"
|
||||
},
|
||||
"total_result": {
|
||||
"type": "string",
|
||||
"format": "uint64"
|
||||
},
|
||||
"result": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1UserGrantView"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1UserGrantView": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"OrgId": {
|
||||
"type": "string"
|
||||
},
|
||||
"ProjectId": {
|
||||
"type": "string"
|
||||
},
|
||||
"UserId": {
|
||||
"type": "string"
|
||||
},
|
||||
"Roles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"OrgName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1UserPhone": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@@ -1,15 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
)
|
||||
|
||||
func (s *Server) SearchMyProjectOrgs(ctx context.Context, request *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) {
|
||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-8kdRf", "Not implemented")
|
||||
}
|
||||
|
||||
func (s *Server) IsIamAdmin(ctx context.Context, _ *empty.Empty) (*IsAdminResponse, error) {
|
||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-9odFv", "Not implemented")
|
||||
}
|
@@ -277,26 +277,6 @@ func (mr *MockAuthServiceClientMockRecorder) Healthz(arg0, arg1 interface{}, arg
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Healthz", reflect.TypeOf((*MockAuthServiceClient)(nil).Healthz), varargs...)
|
||||
}
|
||||
|
||||
// IsIamAdmin mocks base method
|
||||
func (m *MockAuthServiceClient) IsIamAdmin(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.IsAdminResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "IsIamAdmin", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.IsAdminResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// IsIamAdmin indicates an expected call of IsIamAdmin
|
||||
func (mr *MockAuthServiceClientMockRecorder) IsIamAdmin(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsIamAdmin", reflect.TypeOf((*MockAuthServiceClient)(nil).IsIamAdmin), varargs...)
|
||||
}
|
||||
|
||||
// Ready mocks base method
|
||||
func (m *MockAuthServiceClient) Ready(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -397,24 +377,24 @@ func (mr *MockAuthServiceClientMockRecorder) SearchMyProjectOrgs(arg0, arg1 inte
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchMyProjectOrgs", reflect.TypeOf((*MockAuthServiceClient)(nil).SearchMyProjectOrgs), varargs...)
|
||||
}
|
||||
|
||||
// SetMyPassword mocks base method
|
||||
func (m *MockAuthServiceClient) SetMyPassword(arg0 context.Context, arg1 *grpc.PasswordRequest, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
|
||||
// SearchUserGrant mocks base method
|
||||
func (m *MockAuthServiceClient) SearchUserGrant(arg0 context.Context, arg1 *grpc.UserGrantSearchRequest, arg2 ...grpc0.CallOption) (*grpc.UserGrantSearchResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "SetMyPassword", varargs...)
|
||||
ret0, _ := ret[0].(*emptypb.Empty)
|
||||
ret := m.ctrl.Call(m, "SearchUserGrant", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.UserGrantSearchResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SetMyPassword indicates an expected call of SetMyPassword
|
||||
func (mr *MockAuthServiceClientMockRecorder) SetMyPassword(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
// SearchUserGrant indicates an expected call of SearchUserGrant
|
||||
func (mr *MockAuthServiceClientMockRecorder) SearchUserGrant(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMyPassword", reflect.TypeOf((*MockAuthServiceClient)(nil).SetMyPassword), varargs...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUserGrant", reflect.TypeOf((*MockAuthServiceClient)(nil).SearchUserGrant), varargs...)
|
||||
}
|
||||
|
||||
// UpdateMyUserAddress mocks base method
|
||||
@@ -478,14 +458,14 @@ func (mr *MockAuthServiceClientMockRecorder) Validate(arg0, arg1 interface{}, ar
|
||||
}
|
||||
|
||||
// VerifyMfaOTP mocks base method
|
||||
func (m *MockAuthServiceClient) VerifyMfaOTP(arg0 context.Context, arg1 *grpc.VerifyMfaOtp, arg2 ...grpc0.CallOption) (*grpc.MfaOtpResponse, error) {
|
||||
func (m *MockAuthServiceClient) VerifyMfaOTP(arg0 context.Context, arg1 *grpc.VerifyMfaOtp, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "VerifyMfaOTP", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.MfaOtpResponse)
|
||||
ret0, _ := ret[0].(*emptypb.Empty)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
@@ -1,50 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
)
|
||||
|
||||
func (s *Server) GetMyZitadelPermissions(ctx context.Context, _ *empty.Empty) (*MyPermissions, error) {
|
||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-or67G", "Not implemented")
|
||||
//ctxData := auth.GetCtxData(ctx)
|
||||
//
|
||||
//grants, err := s.processor.ResolveGrants(ctx, ctxData.UserID, ctxData.OrgID)
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
//
|
||||
//permissions := &MyPermissions{Permissions: []string{}}
|
||||
//
|
||||
//for _, grant := range grants {
|
||||
// for _, role := range grant.Roles {
|
||||
// roleName, ctxID := auth.SplitPermission(role)
|
||||
// for _, mapping := range s.authConf.RolePermissionMappings {
|
||||
// if mapping.Role == roleName {
|
||||
// permissions.appendPermissions(ctxID, mapping.Permissions...)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//return permissions, nil
|
||||
}
|
||||
|
||||
func (p *MyPermissions) appendPermissions(ctxID string, permissions ...string) {
|
||||
for _, permission := range permissions {
|
||||
p.appendPermission(ctxID, permission)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *MyPermissions) appendPermission(ctxID, permission string) {
|
||||
if ctxID != "" {
|
||||
permission = permission + ":" + ctxID
|
||||
}
|
||||
for _, existingPermission := range p.Permissions {
|
||||
if existingPermission == permission {
|
||||
return
|
||||
}
|
||||
}
|
||||
p.Permissions = append(p.Permissions, permission)
|
||||
}
|
22
pkg/auth/api/grpc/search_converter.go
Normal file
22
pkg/auth/api/grpc/search_converter.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package grpc
|
||||
|
||||
import "github.com/caos/zitadel/internal/model"
|
||||
|
||||
func searchMethodToModel(method SearchMethod) model.SearchMethod {
|
||||
switch method {
|
||||
case SearchMethod_SEARCHMETHOD_EQUALS:
|
||||
return model.SEARCHMETHOD_EQUALS
|
||||
case SearchMethod_SEARCHMETHOD_CONTAINS:
|
||||
return model.SEARCHMETHOD_CONTAINS
|
||||
case SearchMethod_SEARCHMETHOD_STARTS_WITH:
|
||||
return model.SEARCHMETHOD_STARTS_WITH
|
||||
case SearchMethod_SEARCHMETHOD_EQUALS_IGNORE_CASE:
|
||||
return model.SEARCHMETHOD_EQUALS_IGNORE_CASE
|
||||
case SearchMethod_SEARCHMETHOD_CONTAINS_IGNORE_CASE:
|
||||
return model.SEARCHMETHOD_CONTAINS_IGNORE_CASE
|
||||
case SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE:
|
||||
return model.SEARCHMETHOD_STARTS_WITH_IGNORE_CASE
|
||||
default:
|
||||
return model.SEARCHMETHOD_EQUALS
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
@@ -20,12 +21,12 @@ type Server struct {
|
||||
authZ auth_util.Config
|
||||
}
|
||||
|
||||
func StartServer(conf grpc_util.ServerConfig, authZ auth_util.Config, repo repository.Repository) *Server {
|
||||
func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth_util.Config, authRepo repository.Repository) *Server {
|
||||
return &Server{
|
||||
port: conf.Port,
|
||||
repo: repo,
|
||||
repo: authRepo,
|
||||
authZ: authZ,
|
||||
verifier: auth.Start(),
|
||||
verifier: auth.Start(authZRepo),
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -110,7 +110,7 @@ func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *MfaOtpRespon
|
||||
}
|
||||
|
||||
func (s *Server) VerifyMfaOTP(ctx context.Context, request *VerifyMfaOtp) (*empty.Empty, error) {
|
||||
err := s.repo.VerifyMyMfaOTP(ctx, request.Code)
|
||||
err := s.repo.VerifyMyMfaOTPSetup(ctx, request.Code)
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
||||
|
30
pkg/auth/api/grpc/user_grant.go
Normal file
30
pkg/auth/api/grpc/user_grant.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
)
|
||||
|
||||
func (s *Server) SearchMyUserGrant(ctx context.Context, in *UserGrantSearchRequest) (*UserGrantSearchResponse, error) {
|
||||
response, err := s.repo.SearchMyUserGrants(ctx, userGrantSearchRequestsToModel(in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userGrantSearchResponseFromModel(response), nil
|
||||
}
|
||||
|
||||
func (s *Server) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) {
|
||||
response, err := s.repo.SearchMyProjectOrgs(ctx, myProjectOrgSearchRequestRequestsToModel(in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectOrgSearchResponseFromModel(response), nil
|
||||
}
|
||||
|
||||
func (s *Server) GetMyZitadelPermissions(ctx context.Context, _ *empty.Empty) (*MyPermissions, error) {
|
||||
perms, err := s.repo.SearchMyZitadelPermissions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MyPermissions{Permissions: perms}, nil
|
||||
}
|
126
pkg/auth/api/grpc/user_grant_converter.go
Normal file
126
pkg/auth/api/grpc/user_grant_converter.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||
)
|
||||
|
||||
func userGrantSearchRequestsToModel(request *UserGrantSearchRequest) *grant_model.UserGrantSearchRequest {
|
||||
return &grant_model.UserGrantSearchRequest{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
Queries: userGrantSearchQueriesToModel(request.Queries),
|
||||
}
|
||||
}
|
||||
|
||||
func userGrantSearchQueriesToModel(queries []*UserGrantSearchQuery) []*grant_model.UserGrantSearchQuery {
|
||||
converted := make([]*grant_model.UserGrantSearchQuery, len(queries))
|
||||
for i, q := range queries {
|
||||
converted[i] = userGrantSearchQueryToModel(q)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func userGrantSearchQueryToModel(query *UserGrantSearchQuery) *grant_model.UserGrantSearchQuery {
|
||||
return &grant_model.UserGrantSearchQuery{
|
||||
Key: userGrantSearchKeyToModel(query.Key),
|
||||
Method: searchMethodToModel(query.Method),
|
||||
Value: query.Value,
|
||||
}
|
||||
}
|
||||
|
||||
func userGrantSearchKeyToModel(key UserGrantSearchKey) grant_model.UserGrantSearchKey {
|
||||
switch key {
|
||||
case UserGrantSearchKey_UserGrantSearchKey_ORG_ID:
|
||||
return grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER
|
||||
case UserGrantSearchKey_UserGrantSearchKey_PROJECT_ID:
|
||||
return grant_model.USERGRANTSEARCHKEY_PROJECT_ID
|
||||
default:
|
||||
return grant_model.USERGRANTSEARCHKEY_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func myProjectOrgSearchRequestRequestsToModel(request *MyProjectOrgSearchRequest) *grant_model.UserGrantSearchRequest {
|
||||
return &grant_model.UserGrantSearchRequest{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
Asc: request.Asc,
|
||||
SortingColumn: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER,
|
||||
Queries: myProjectOrgSearchQueriesToModel(request.Queries),
|
||||
}
|
||||
}
|
||||
|
||||
func myProjectOrgSearchQueriesToModel(queries []*MyProjectOrgSearchQuery) []*grant_model.UserGrantSearchQuery {
|
||||
converted := make([]*grant_model.UserGrantSearchQuery, len(queries))
|
||||
for i, q := range queries {
|
||||
converted[i] = myProjectOrgSearchQueryToModel(q)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func myProjectOrgSearchQueryToModel(query *MyProjectOrgSearchQuery) *grant_model.UserGrantSearchQuery {
|
||||
return &grant_model.UserGrantSearchQuery{
|
||||
Key: myProjectOrgSearchKeyToModel(query.Key),
|
||||
Method: searchMethodToModel(query.Method),
|
||||
Value: query.Value,
|
||||
}
|
||||
}
|
||||
|
||||
func myProjectOrgSearchKeyToModel(key MyProjectOrgSearchKey) grant_model.UserGrantSearchKey {
|
||||
switch key {
|
||||
case MyProjectOrgSearchKey_MYPROJECTORGSEARCHKEY_ORG_NAME:
|
||||
return grant_model.USERGRANTSEARCHKEY_ORG_NAME
|
||||
default:
|
||||
return grant_model.USERGRANTSEARCHKEY_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func userGrantSearchResponseFromModel(response *grant_model.UserGrantSearchResponse) *UserGrantSearchResponse {
|
||||
return &UserGrantSearchResponse{
|
||||
Offset: response.Offset,
|
||||
Limit: response.Limit,
|
||||
TotalResult: response.TotalResult,
|
||||
Result: userGrantViewsFromModel(response.Result),
|
||||
}
|
||||
}
|
||||
|
||||
func userGrantViewsFromModel(users []*grant_model.UserGrantView) []*UserGrantView {
|
||||
converted := make([]*UserGrantView, len(users))
|
||||
for i, user := range users {
|
||||
converted[i] = userGrantViewFromModel(user)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func userGrantViewFromModel(grant *grant_model.UserGrantView) *UserGrantView {
|
||||
return &UserGrantView{
|
||||
UserId: grant.UserID,
|
||||
OrgId: grant.ResourceOwner,
|
||||
OrgName: grant.OrgName,
|
||||
ProjectId: grant.ProjectID,
|
||||
Roles: grant.RoleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func projectOrgSearchResponseFromModel(response *grant_model.ProjectOrgSearchResponse) *MyProjectOrgSearchResponse {
|
||||
return &MyProjectOrgSearchResponse{
|
||||
Offset: response.Offset,
|
||||
Limit: response.Limit,
|
||||
TotalResult: response.TotalResult,
|
||||
Result: projectOrgsFromModel(response.Result),
|
||||
}
|
||||
}
|
||||
|
||||
func projectOrgsFromModel(projectOrgs []*grant_model.Org) []*Org {
|
||||
converted := make([]*Org, len(projectOrgs))
|
||||
for i, org := range projectOrgs {
|
||||
converted[i] = projectOrgFromModel(org)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func projectOrgFromModel(org *grant_model.Org) *Org {
|
||||
return &Org{
|
||||
Id: org.OrgID,
|
||||
Name: org.OrgName,
|
||||
}
|
||||
}
|
@@ -2,10 +2,13 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
)
|
||||
|
||||
func (s *Server) GetMyUserSessions(ctx context.Context, _ *empty.Empty) (_ *UserSessionViews, err error) {
|
||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-nc52s", "Not implemented")
|
||||
userSessions, err := s.repo.GetMyUserSessions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UserSessionViews{UserSessions: userSessionViewsFromModel(userSessions)}, nil
|
||||
}
|
||||
|
35
pkg/auth/api/grpc/user_session_converter.go
Normal file
35
pkg/auth/api/grpc/user_session_converter.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
auth_req_model "github.com/caos/zitadel/internal/auth_request/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
)
|
||||
|
||||
func userSessionViewsFromModel(userSessions []*usr_model.UserSessionView) []*UserSessionView {
|
||||
converted := make([]*UserSessionView, len(userSessions))
|
||||
for i, s := range userSessions {
|
||||
converted[i] = userSessionViewFromModel(s)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func userSessionViewFromModel(userSession *usr_model.UserSessionView) *UserSessionView {
|
||||
return &UserSessionView{
|
||||
Sequence: userSession.Sequence,
|
||||
AgentId: userSession.UserAgentID,
|
||||
UserId: userSession.UserID,
|
||||
UserName: userSession.UserName,
|
||||
AuthState: userSessionStateFromModel(userSession.State),
|
||||
}
|
||||
}
|
||||
|
||||
func userSessionStateFromModel(state auth_req_model.UserSessionState) UserSessionState {
|
||||
switch state {
|
||||
case auth_req_model.UserSessionStateActive:
|
||||
return UserSessionState_USERSESSIONSTATE_ACTIVE
|
||||
case auth_req_model.UserSessionStateTerminated:
|
||||
return UserSessionState_USERSESSIONSTATE_TERMINATED
|
||||
default:
|
||||
return UserSessionState_USERSESSIONSTATE_UNSPECIFIED
|
||||
}
|
||||
}
|
82
pkg/auth/api/oidc/auth_request.go
Normal file
82
pkg/auth/api/oidc/auth_request.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/caos/zitadel/internal/auth_request/model"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (op.AuthRequest, error) {
|
||||
userAgentID, ok := UserAgentIDFromCtx(ctx)
|
||||
if !ok {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id")
|
||||
}
|
||||
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
|
||||
resp, err := o.repo.CreateAuthRequest(ctx, authRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return AuthRequestFromBusiness(resp)
|
||||
}
|
||||
|
||||
func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (op.AuthRequest, error) {
|
||||
resp, err := o.repo.AuthRequestByIDCheckLoggedIn(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return AuthRequestFromBusiness(resp)
|
||||
}
|
||||
|
||||
func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (op.AuthRequest, error) {
|
||||
resp, err := o.repo.AuthRequestByCode(ctx, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return AuthRequestFromBusiness(resp)
|
||||
}
|
||||
|
||||
func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) error {
|
||||
return o.repo.SaveAuthCode(ctx, id, code)
|
||||
}
|
||||
|
||||
func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) error {
|
||||
return o.repo.DeleteAuthRequest(ctx, id)
|
||||
}
|
||||
|
||||
func (o *OPStorage) CreateToken(ctx context.Context, authReq op.AuthRequest) (string, time.Time, error) {
|
||||
req, err := o.repo.AuthRequestByID(ctx, authReq.GetID())
|
||||
if err != nil {
|
||||
return "", time.Time{}, err
|
||||
}
|
||||
resp, err := o.repo.CreateToken(ctx, req.AgentID, req.ApplicationID, req.UserID, req.Audience, req.Request.(*model.AuthRequestOIDC).Scopes, o.defaultAccessTokenLifetime) //PLANNED: lifetime from client
|
||||
if err != nil {
|
||||
return "", time.Time{}, err
|
||||
}
|
||||
return resp.ID, resp.Expiration, nil
|
||||
}
|
||||
|
||||
func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID string) error {
|
||||
userAgentID, ok := UserAgentIDFromCtx(ctx)
|
||||
if !ok {
|
||||
return errors.ThrowPreconditionFailed(nil, "OIDC-fso7F", "no user agent id")
|
||||
}
|
||||
return o.repo.SignOut(ctx, userAgentID, userID)
|
||||
}
|
||||
|
||||
func (o *OPStorage) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, timer <-chan time.Time) {
|
||||
o.repo.GetSigningKey(ctx, keyCh, errCh, timer)
|
||||
}
|
||||
|
||||
func (o *OPStorage) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) {
|
||||
return o.repo.GetKeySet(ctx)
|
||||
}
|
||||
|
||||
func (o *OPStorage) SaveNewKeyPair(ctx context.Context) error {
|
||||
return o.repo.GenerateSigningKeyPair(ctx, o.signingKeyAlgorithm)
|
||||
}
|
254
pkg/auth/api/oidc/auth_request_converter.go
Normal file
254
pkg/auth/api/oidc/auth_request_converter.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
api_utils "github.com/caos/zitadel/internal/api"
|
||||
http_utils "github.com/caos/zitadel/internal/api/http"
|
||||
"github.com/caos/zitadel/internal/auth_request/model"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
amrPassword = "password"
|
||||
amrMFA = "mfa"
|
||||
amrOTP = "otp"
|
||||
)
|
||||
|
||||
type AuthRequest struct {
|
||||
*model.AuthRequest
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetID() string {
|
||||
return a.ID
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetACR() string {
|
||||
// return a.
|
||||
return "" //PLANNED: impl
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetAMR() []string {
|
||||
amr := make([]string, 0)
|
||||
if a.PasswordVerified {
|
||||
amr = append(amr, amrPassword)
|
||||
}
|
||||
if len(a.MfasVerified) > 0 {
|
||||
amr = append(amr, amrMFA)
|
||||
for _, mfa := range a.MfasVerified {
|
||||
if amrMfa := AMRFromMFAType(mfa); amrMfa != "" {
|
||||
amr = append(amr, amrMfa)
|
||||
}
|
||||
}
|
||||
}
|
||||
return amr
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetAudience() []string {
|
||||
return a.Audience
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetAuthTime() time.Time {
|
||||
return a.AuthTime
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetClientID() string {
|
||||
return a.ApplicationID
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetCodeChallenge() *oidc.CodeChallenge {
|
||||
return CodeChallengeToOIDC(a.oidc().CodeChallenge)
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetNonce() string {
|
||||
return a.oidc().Nonce
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetRedirectURI() string {
|
||||
return a.CallbackURI
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetResponseType() oidc.ResponseType {
|
||||
return ResponseTypeToOIDC(a.oidc().ResponseType)
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetScopes() []string {
|
||||
return a.oidc().Scopes
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetState() string {
|
||||
return a.TransferState
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetSubject() string {
|
||||
return a.UserID
|
||||
}
|
||||
|
||||
func (a *AuthRequest) Done() bool {
|
||||
for _, step := range a.PossibleSteps {
|
||||
if step.Type() == model.NextStepRedirectToCallback {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *AuthRequest) oidc() *model.AuthRequestOIDC {
|
||||
return a.Request.(*model.AuthRequestOIDC)
|
||||
}
|
||||
|
||||
func AuthRequestFromBusiness(authReq *model.AuthRequest) (_ op.AuthRequest, err error) {
|
||||
if _, ok := authReq.Request.(*model.AuthRequestOIDC); !ok {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "OIDC-Haz7A", "auth request is not of type oidc")
|
||||
}
|
||||
return &AuthRequest{authReq}, nil
|
||||
}
|
||||
|
||||
func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, userAgentID, userID string) *model.AuthRequest {
|
||||
return &model.AuthRequest{
|
||||
AgentID: userAgentID,
|
||||
BrowserInfo: ParseBrowserInfoFromContext(ctx),
|
||||
ApplicationID: authReq.ClientID,
|
||||
CallbackURI: authReq.RedirectURI,
|
||||
TransferState: authReq.State,
|
||||
Prompt: PromptToBusiness(authReq.Prompt),
|
||||
PossibleLOAs: ACRValuesToBusiness(authReq.ACRValues),
|
||||
UiLocales: UILocalesToBusiness(authReq.UILocales),
|
||||
LoginHint: authReq.LoginHint,
|
||||
MaxAuthAge: authReq.MaxAge,
|
||||
UserID: userID,
|
||||
Request: &model.AuthRequestOIDC{
|
||||
Scopes: authReq.Scopes,
|
||||
ResponseType: ResponseTypeToBusiness(authReq.ResponseType),
|
||||
Nonce: authReq.Nonce,
|
||||
CodeChallenge: CodeChallengeToBusiness(authReq.CodeChallenge, authReq.CodeChallengeMethod),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ParseBrowserInfoFromContext(ctx context.Context) *model.BrowserInfo {
|
||||
userAgent, acceptLang := HttpHeadersFromContext(ctx)
|
||||
ip := IpFromContext(ctx)
|
||||
return &model.BrowserInfo{RemoteIP: ip, UserAgent: userAgent, AcceptLanguage: acceptLang}
|
||||
}
|
||||
|
||||
func HttpHeadersFromContext(ctx context.Context) (userAgent, acceptLang string) {
|
||||
ctxHeaders, ok := http_utils.HeadersFromCtx(ctx)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if agents, ok := ctxHeaders[api_utils.UserAgent]; ok {
|
||||
userAgent = agents[0]
|
||||
}
|
||||
if langs, ok := ctxHeaders[api_utils.AcceptLanguage]; ok {
|
||||
acceptLang = langs[0]
|
||||
}
|
||||
return userAgent, acceptLang
|
||||
}
|
||||
|
||||
func IpFromContext(ctx context.Context) net.IP {
|
||||
ipString := http_utils.RemoteIPFromCtx(ctx)
|
||||
if ipString == "" {
|
||||
return nil
|
||||
}
|
||||
return net.ParseIP(ipString)
|
||||
}
|
||||
|
||||
func PromptToBusiness(prompt oidc.Prompt) model.Prompt {
|
||||
switch prompt {
|
||||
case oidc.PromptNone:
|
||||
return model.PromptNone
|
||||
case oidc.PromptLogin:
|
||||
return model.PromptLogin
|
||||
case oidc.PromptConsent:
|
||||
return model.PromptConsent
|
||||
case oidc.PromptSelectAccount:
|
||||
return model.PromptSelectAccount
|
||||
default:
|
||||
return model.PromptUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func ACRValuesToBusiness(values []string) []model.LevelOfAssurance {
|
||||
return nil
|
||||
}
|
||||
|
||||
func UILocalesToBusiness(tags []language.Tag) []string {
|
||||
if tags == nil {
|
||||
return nil
|
||||
}
|
||||
locales := make([]string, len(tags))
|
||||
for i, tag := range tags {
|
||||
locales[i] = tag.String()
|
||||
}
|
||||
return locales
|
||||
}
|
||||
|
||||
func ResponseTypeToBusiness(responseType oidc.ResponseType) model.OIDCResponseType {
|
||||
switch responseType {
|
||||
case oidc.ResponseTypeCode:
|
||||
return model.OIDCResponseTypeCode
|
||||
case oidc.ResponseTypeIDToken:
|
||||
return model.OIDCResponseTypeIdToken
|
||||
case oidc.ResponseTypeIDTokenOnly:
|
||||
return model.OIDCResponseTypeToken
|
||||
default:
|
||||
return model.OIDCResponseTypeCode
|
||||
}
|
||||
}
|
||||
|
||||
func ResponseTypeToOIDC(responseType model.OIDCResponseType) oidc.ResponseType {
|
||||
switch responseType {
|
||||
case model.OIDCResponseTypeCode:
|
||||
return oidc.ResponseTypeCode
|
||||
case model.OIDCResponseTypeToken:
|
||||
return oidc.ResponseTypeIDToken
|
||||
case model.OIDCResponseTypeIdToken:
|
||||
return oidc.ResponseTypeIDTokenOnly
|
||||
default:
|
||||
return oidc.ResponseTypeCode
|
||||
}
|
||||
}
|
||||
|
||||
func CodeChallengeToBusiness(challenge string, method oidc.CodeChallengeMethod) *model.OIDCCodeChallenge {
|
||||
if challenge == "" {
|
||||
return nil
|
||||
}
|
||||
challengeMethod := model.CodeChallengeMethodPlain
|
||||
if method == oidc.CodeChallengeMethodS256 {
|
||||
challengeMethod = model.CodeChallengeMethodS256
|
||||
}
|
||||
return &model.OIDCCodeChallenge{
|
||||
Challenge: challenge,
|
||||
Method: challengeMethod,
|
||||
}
|
||||
}
|
||||
|
||||
func CodeChallengeToOIDC(challenge *model.OIDCCodeChallenge) *oidc.CodeChallenge {
|
||||
if challenge == nil {
|
||||
return nil
|
||||
}
|
||||
challengeMethod := oidc.CodeChallengeMethodPlain
|
||||
if challenge.Method == model.CodeChallengeMethodS256 {
|
||||
challengeMethod = oidc.CodeChallengeMethodS256
|
||||
}
|
||||
return &oidc.CodeChallenge{
|
||||
Challenge: challenge.Challenge,
|
||||
Method: challengeMethod,
|
||||
}
|
||||
}
|
||||
|
||||
func AMRFromMFAType(mfaType model.MfaType) string {
|
||||
switch mfaType {
|
||||
case model.MfaTypeOTP:
|
||||
return amrOTP
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
97
pkg/auth/api/oidc/client.go
Normal file
97
pkg/auth/api/oidc/client.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
|
||||
"github.com/caos/zitadel/internal/user/model"
|
||||
)
|
||||
|
||||
const (
|
||||
scopeOpenID = "openid"
|
||||
scopeProfile = "profile"
|
||||
scopeEmail = "email"
|
||||
scopePhone = "phone"
|
||||
scopeAddress = "address"
|
||||
)
|
||||
|
||||
func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (op.Client, error) {
|
||||
client, err := o.repo.ApplicationByClientID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ClientFromBusiness(client, o.defaultLoginURL, o.defaultAccessTokenLifetime, o.defaultIdTokenLifetime)
|
||||
}
|
||||
|
||||
func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) error {
|
||||
return o.repo.AuthorizeOIDCApplication(ctx, id, secret)
|
||||
}
|
||||
|
||||
func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID string) (*oidc.Userinfo, error) {
|
||||
token, err := o.repo.TokenByID(ctx, tokenID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.GetUserinfoFromScopes(ctx, token.UserID, token.Scopes)
|
||||
}
|
||||
|
||||
func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID string, scopes []string) (*oidc.Userinfo, error) {
|
||||
user, err := o.repo.UserByID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userInfo := new(oidc.Userinfo)
|
||||
for _, scope := range scopes {
|
||||
switch scope {
|
||||
case scopeOpenID:
|
||||
userInfo.Subject = user.AggregateID
|
||||
case scopeEmail:
|
||||
if user.Email == nil {
|
||||
continue
|
||||
}
|
||||
userInfo.Email = user.EmailAddress
|
||||
userInfo.EmailVerified = user.IsEmailVerified
|
||||
case scopeProfile:
|
||||
if user.Profile == nil {
|
||||
continue
|
||||
}
|
||||
userInfo.Name = user.FirstName + " " + user.LastName
|
||||
userInfo.FamilyName = user.LastName
|
||||
userInfo.GivenName = user.FirstName
|
||||
userInfo.Nickname = user.NickName
|
||||
userInfo.PreferredUsername = user.UserName
|
||||
userInfo.UpdatedAt = user.ChangeDate
|
||||
userInfo.Gender = oidc.Gender(getGender(user.Gender))
|
||||
case scopePhone:
|
||||
if user.Phone == nil {
|
||||
continue
|
||||
}
|
||||
userInfo.PhoneNumber = user.PhoneNumber
|
||||
userInfo.PhoneNumberVerified = user.IsPhoneVerified
|
||||
case scopeAddress:
|
||||
if user.Address == nil {
|
||||
continue
|
||||
}
|
||||
userInfo.Address.StreetAddress = user.StreetAddress
|
||||
userInfo.Address.Locality = user.Locality
|
||||
userInfo.Address.Region = user.Region
|
||||
userInfo.Address.PostalCode = user.PostalCode
|
||||
userInfo.Address.Country = user.Country
|
||||
}
|
||||
}
|
||||
return userInfo, nil
|
||||
}
|
||||
|
||||
func getGender(gender model.Gender) string {
|
||||
switch gender {
|
||||
case model.GENDER_FEMALE:
|
||||
return "female"
|
||||
case model.GENDER_MALE:
|
||||
return "male"
|
||||
case model.GENDER_DIVERSE:
|
||||
return "diverse"
|
||||
}
|
||||
return ""
|
||||
}
|
73
pkg/auth/api/oidc/client_converter.go
Normal file
73
pkg/auth/api/oidc/client_converter.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
*model.ApplicationView
|
||||
defaultLoginURL string
|
||||
defaultAccessTokenLifetime time.Duration
|
||||
defaultIdTokenLifetime time.Duration
|
||||
}
|
||||
|
||||
func ClientFromBusiness(app *model.ApplicationView, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration) (op.Client, error) {
|
||||
if !app.IsOIDC {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "OIDC-d5bhD", "client is not a proper oidc application")
|
||||
}
|
||||
return &Client{ApplicationView: app, defaultLoginURL: defaultLoginURL, defaultAccessTokenLifetime: defaultAccessTokenLifetime, defaultIdTokenLifetime: defaultIdTokenLifetime}, nil
|
||||
}
|
||||
|
||||
func (c *Client) ApplicationType() op.ApplicationType {
|
||||
return op.ApplicationType(c.OIDCApplicationType)
|
||||
}
|
||||
|
||||
func (c *Client) GetAuthMethod() op.AuthMethod {
|
||||
return authMethodToOIDC(c.OIDCAuthMethodType)
|
||||
}
|
||||
|
||||
func (c *Client) GetID() string {
|
||||
return c.OIDCClientID
|
||||
}
|
||||
|
||||
func (c *Client) LoginURL(id string) string {
|
||||
return c.defaultLoginURL + id
|
||||
}
|
||||
|
||||
func (c *Client) RedirectURIs() []string {
|
||||
return c.OIDCRedirectUris
|
||||
}
|
||||
|
||||
func (c *Client) PostLogoutRedirectURIs() []string {
|
||||
return c.OIDCPostLogoutRedirectUris
|
||||
}
|
||||
|
||||
func (c *Client) AccessTokenLifetime() time.Duration {
|
||||
return c.defaultAccessTokenLifetime //PLANNED: impl from real client
|
||||
}
|
||||
|
||||
func (c *Client) IDTokenLifetime() time.Duration {
|
||||
return c.defaultIdTokenLifetime //PLANNED: impl from real client
|
||||
}
|
||||
|
||||
func (c *Client) AccessTokenType() op.AccessTokenType {
|
||||
return op.AccessTokenTypeBearer //PLANNED: impl from real client
|
||||
}
|
||||
|
||||
func authMethodToOIDC(authType model.OIDCAuthMethodType) op.AuthMethod {
|
||||
switch authType {
|
||||
case model.OIDCAUTHMETHODTYPE_BASIC:
|
||||
return op.AuthMethodBasic
|
||||
case model.OIDCAUTHMETHODTYPE_POST:
|
||||
return op.AuthMethodPost
|
||||
case model.OIDCAUTHMETHODTYPE_NONE:
|
||||
return op.AuthMethodNone
|
||||
default:
|
||||
return op.AuthMethodBasic
|
||||
}
|
||||
}
|
37
pkg/auth/api/oidc/cookie_interceptor.go
Normal file
37
pkg/auth/api/oidc/cookie_interceptor.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
http_utils "github.com/caos/zitadel/internal/api/http"
|
||||
)
|
||||
|
||||
type key int
|
||||
|
||||
var (
|
||||
userAgentKey key
|
||||
)
|
||||
|
||||
func UserAgentIDFromCtx(ctx context.Context) (string, bool) {
|
||||
userAgentID, ok := ctx.Value(userAgentKey).(string)
|
||||
return userAgentID, ok
|
||||
}
|
||||
|
||||
func UserAgentCookieHandler(cookieHandler *http_utils.UserAgentHandler, nextHandlerFunc func(http.HandlerFunc) http.HandlerFunc) func(http.HandlerFunc) http.HandlerFunc {
|
||||
return func(handlerFunc http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ua, err := cookieHandler.GetUserAgent(r)
|
||||
if err != nil {
|
||||
ua, err = cookieHandler.NewUserAgent()
|
||||
}
|
||||
if err == nil {
|
||||
ctx := context.WithValue(r.Context(), userAgentKey, ua.ID)
|
||||
r = r.WithContext(ctx)
|
||||
cookieHandler.SetUserAgent(w, ua)
|
||||
}
|
||||
handlerFunc(w, r)
|
||||
nextHandlerFunc(handlerFunc)
|
||||
}
|
||||
}
|
||||
}
|
87
pkg/auth/api/oidc/op.go
Normal file
87
pkg/auth/api/oidc/op.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
|
||||
http_utils "github.com/caos/zitadel/internal/api/http"
|
||||
"github.com/caos/zitadel/internal/auth/repository"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
)
|
||||
|
||||
type OPHandlerConfig struct {
|
||||
OPConfig *op.Config
|
||||
StorageConfig StorageConfig
|
||||
UserAgentCookieConfig *http_utils.UserAgentCookieConfig
|
||||
Endpoints *EndpointConfig
|
||||
}
|
||||
|
||||
type StorageConfig struct {
|
||||
DefaultLoginURL string
|
||||
SigningKeyAlgorithm string
|
||||
DefaultAccessTokenLifetime types.Duration
|
||||
DefaultIdTokenLifetime types.Duration
|
||||
}
|
||||
|
||||
type EndpointConfig struct {
|
||||
Auth *Endpoint
|
||||
Token *Endpoint
|
||||
Userinfo *Endpoint
|
||||
EndSession *Endpoint
|
||||
Keys *Endpoint
|
||||
}
|
||||
|
||||
type Endpoint struct {
|
||||
Path string
|
||||
URL string
|
||||
}
|
||||
|
||||
type OPStorage struct {
|
||||
repo repository.Repository
|
||||
defaultLoginURL string
|
||||
defaultAccessTokenLifetime time.Duration
|
||||
defaultIdTokenLifetime time.Duration
|
||||
signingKeyAlgorithm string
|
||||
}
|
||||
|
||||
func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Repository) op.OpenIDProvider {
|
||||
cookieHandler, err := http_utils.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator)
|
||||
logging.Log("OIDC-sd4fd").OnError(err).Panic("cannot user agent handler")
|
||||
provider, err := op.NewDefaultOP(
|
||||
ctx,
|
||||
config.OPConfig,
|
||||
newStorage(config.StorageConfig, repo),
|
||||
op.WithHttpInterceptor(
|
||||
UserAgentCookieHandler(
|
||||
cookieHandler,
|
||||
http_utils.CopyHeadersToContext,
|
||||
),
|
||||
),
|
||||
op.WithCustomAuthEndpoint(op.NewEndpointWithURL(config.Endpoints.Auth.Path, config.Endpoints.Auth.URL)),
|
||||
op.WithCustomTokenEndpoint(op.NewEndpointWithURL(config.Endpoints.Token.Path, config.Endpoints.Token.URL)),
|
||||
op.WithCustomUserinfoEndpoint(op.NewEndpointWithURL(config.Endpoints.Userinfo.Path, config.Endpoints.Userinfo.URL)),
|
||||
op.WithCustomEndSessionEndpoint(op.NewEndpointWithURL(config.Endpoints.EndSession.Path, config.Endpoints.EndSession.URL)),
|
||||
op.WithCustomKeysEndpoint(op.NewEndpointWithURL(config.Endpoints.Keys.Path, config.Endpoints.Keys.URL)),
|
||||
op.WithRetry(3, time.Duration(30*time.Second)),
|
||||
)
|
||||
logging.Log("OIDC-asf13").OnError(err).Panic("cannot create provider")
|
||||
return provider
|
||||
}
|
||||
|
||||
func newStorage(config StorageConfig, repo repository.Repository) *OPStorage {
|
||||
return &OPStorage{
|
||||
repo: repo,
|
||||
defaultLoginURL: config.DefaultLoginURL,
|
||||
signingKeyAlgorithm: config.SigningKeyAlgorithm,
|
||||
defaultAccessTokenLifetime: config.DefaultAccessTokenLifetime.Duration,
|
||||
defaultIdTokenLifetime: config.DefaultIdTokenLifetime.Duration,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OPStorage) Health(ctx context.Context) error {
|
||||
return o.repo.Health(ctx)
|
||||
}
|
@@ -243,20 +243,20 @@ service AuthService {
|
||||
};
|
||||
}
|
||||
|
||||
rpc SearchMyProjectOrgs(MyProjectOrgSearchRequest) returns (MyProjectOrgSearchResponse) {
|
||||
rpc SearchMyUserGrant(UserGrantSearchRequest) returns (UserGrantSearchResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/global/projectorgs/_search"
|
||||
post: "/usergrants/me/_search"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (caos.zitadel.utils.v1.auth_option) = {
|
||||
permission: "authenticated"
|
||||
};
|
||||
}
|
||||
|
||||
rpc IsIamAdmin(google.protobuf.Empty) returns (IsAdminResponse) {
|
||||
rpc SearchMyProjectOrgs(MyProjectOrgSearchRequest) returns (MyProjectOrgSearchResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/global/_isiamadmin"
|
||||
post: "/global/projectorgs/_search"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (caos.zitadel.utils.v1.auth_option) = {
|
||||
@@ -478,6 +478,41 @@ message OIDCClientAuth {
|
||||
string client_secret = 2;
|
||||
}
|
||||
|
||||
message UserGrantSearchRequest {
|
||||
uint64 offset = 1;
|
||||
uint64 limit = 2;
|
||||
UserGrantSearchKey sorting_column = 3 [(validate.rules).enum = {not_in: [0]}];;
|
||||
bool asc = 4;
|
||||
repeated UserGrantSearchQuery queries = 5;
|
||||
}
|
||||
|
||||
message UserGrantSearchQuery {
|
||||
UserGrantSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];;
|
||||
SearchMethod method = 2;
|
||||
string value = 3;
|
||||
}
|
||||
|
||||
enum UserGrantSearchKey {
|
||||
UserGrantSearchKey_UNKNOWN = 0;
|
||||
UserGrantSearchKey_ORG_ID = 1;
|
||||
UserGrantSearchKey_PROJECT_ID = 2;
|
||||
}
|
||||
|
||||
message UserGrantSearchResponse {
|
||||
uint64 offset = 1;
|
||||
uint64 limit = 2;
|
||||
uint64 total_result = 3;
|
||||
repeated UserGrantView result = 4;
|
||||
}
|
||||
|
||||
message UserGrantView {
|
||||
string OrgId = 1;
|
||||
string ProjectId = 2;
|
||||
string UserId = 3;
|
||||
repeated string Roles = 4;
|
||||
string OrgName = 5;
|
||||
}
|
||||
|
||||
message MyProjectOrgSearchRequest {
|
||||
uint64 offset = 1;
|
||||
uint64 limit = 2;
|
||||
@@ -503,10 +538,6 @@ message MyProjectOrgSearchResponse {
|
||||
repeated Org result = 4;
|
||||
}
|
||||
|
||||
message IsAdminResponse {
|
||||
bool is_admin = 1;
|
||||
}
|
||||
|
||||
message Org {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
@@ -520,4 +551,7 @@ enum SearchMethod {
|
||||
SEARCHMETHOD_EQUALS = 0;
|
||||
SEARCHMETHOD_STARTS_WITH = 1;
|
||||
SEARCHMETHOD_CONTAINS = 2;
|
||||
}
|
||||
SEARCHMETHOD_EQUALS_IGNORE_CASE = 3;
|
||||
SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4;
|
||||
SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5;
|
||||
}
|
||||
|
@@ -2,8 +2,7 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/logging"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing"
|
||||
@@ -16,9 +15,6 @@ type Config struct {
|
||||
Repository eventsourcing.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
||||
repo, err := eventsourcing.Start(config.Repository, systemDefaults)
|
||||
logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app")
|
||||
|
||||
api.Start(ctx, config.API, authZ, repo)
|
||||
func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults, authRepo *eventsourcing.EsRepository) {
|
||||
api.Start(ctx, config.API, authZRepo, authZ, authRepo)
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
//go:generate statik -src=../../console/dist/app
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
@@ -31,7 +29,7 @@ func (i *spaHandler) Open(name string) (http.File, error) {
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config) error {
|
||||
statikFS, err := fs.New()
|
||||
statikFS, err := fs.NewWithNamespace("console")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
3
pkg/console/statik/generate.go
Normal file
3
pkg/console/statik/generate.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package statik
|
||||
|
||||
//go:generate statik -src=../../../console/dist/app -dest=.. -ns=console
|
@@ -1 +0,0 @@
|
||||
package statik
|
@@ -1,14 +0,0 @@
|
||||
package eventstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config) error {
|
||||
return errors.ThrowUnimplemented(nil, "EVENT-1hfiu", "not implemented yet") //TODO: implement
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
package api
|
||||
|
||||
type Config struct {
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
app "github.com/caos/zitadel/internal/login"
|
||||
"github.com/caos/zitadel/pkg/login/api"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
App app.Config
|
||||
API api.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config) error {
|
||||
return errors.ThrowUnimplemented(nil, "LOGIN-3fwvD", "not implemented yet") //TODO: implement
|
||||
}
|
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/management/repository"
|
||||
|
||||
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
||||
@@ -14,8 +15,8 @@ type Config struct {
|
||||
GRPC grpc_util.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, conf Config, authZ auth.Config, repo repository.Repository) {
|
||||
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo)
|
||||
func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) {
|
||||
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, repo)
|
||||
grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig())
|
||||
|
||||
server.StartServer(ctx, grpcServer)
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
||||
"github.com/caos/zitadel/internal/api/grpc/server/middleware"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
mgmt_auth "github.com/caos/zitadel/internal/management/auth"
|
||||
"github.com/caos/zitadel/internal/management/repository"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
@@ -23,7 +24,7 @@ type Server struct {
|
||||
authZ auth.Config
|
||||
}
|
||||
|
||||
func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository.Repository) *Server {
|
||||
func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server {
|
||||
return &Server{
|
||||
port: conf.Port,
|
||||
project: repo,
|
||||
@@ -32,7 +33,7 @@ func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository
|
||||
user: repo,
|
||||
usergrant: repo,
|
||||
authZ: authZ,
|
||||
verifier: mgmt_auth.Start(),
|
||||
verifier: mgmt_auth.Start(authZRepo),
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing"
|
||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/pkg/management/api"
|
||||
@@ -15,7 +16,7 @@ type Config struct {
|
||||
API api.Config
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
||||
func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
||||
roles := make([]string, len(authZ.RolePermissionMappings))
|
||||
for i, role := range authZ.RolePermissionMappings {
|
||||
roles[i] = role.Role
|
||||
@@ -23,5 +24,5 @@ func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults
|
||||
repo, err := eventsourcing.Start(config.Repository, systemDefaults, roles)
|
||||
logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app")
|
||||
|
||||
api.Start(ctx, config.API, authZ, repo)
|
||||
api.Start(ctx, config.API, authZRepo, authZ, repo)
|
||||
}
|
||||
|
Reference in New Issue
Block a user