feat(api): new session service (#5801)

* backup new protoc plugin

* backup

* session

* backup

* initial implementation

* change to specific events

* implement tests

* cleanup

* refactor: use new protoc plugin for api v2

* change package

* simplify code

* cleanup

* cleanup

* fix merge

* start queries

* fix tests

* improve returned values

* add token to projection

* tests

* test db map

* update query

* permission checks

* fix tests and linting

* rework token creation

* i18n

* refactor token check and fix tests

* session to PB test

* request to query tests

* cleanup proto

* test user check

* add comment

* simplify database map type

* Update docs/docs/guides/integrate/access-zitadel-system-api.md

Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>

* fix test

* cleanup

* docs

---------

Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
Livio Spring
2023-05-05 17:34:53 +02:00
committed by GitHub
parent 74377c2c37
commit c2cb84cd24
55 changed files with 3911 additions and 106 deletions

View File

@@ -11,9 +11,35 @@ import "validate/validate.proto";
message Organisation {
oneof org {
string org_id = 1;
string org_domain = 2;
}
}
message ListQuery {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
json_schema: {
title: "General List Query"
description: "Object unspecific list filters like offset, limit and asc/desc."
}
};
uint64 offset = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"0\"";
}
];
uint32 limit = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "100";
description: "Maximum amount of events returned. The default is set to 1000 in https://github.com/zitadel/zitadel/blob/new-eventstore/cmd/zitadel/startup.yaml. If the limit exceeds the maximum configured ZITADEL will throw an error. If no limit is present the default is taken.";
}
];
bool asc = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "default is descending"
}
];
}
message Details {
//sequence represents the order of events. It's always counting
//
@@ -38,3 +64,21 @@ message Details {
}
];
}
message ListDetails {
uint64 total_result = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2\"";
}
];
uint64 processed_sequence = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"267831\"";
}
];
google.protobuf.Timestamp timestamp = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "the last time the projection got updated"
}
];
}

View File

@@ -2,11 +2,90 @@ syntax = "proto3";
package zitadel.session.v2alpha;
import "zitadel/user/v2alpha/user.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/timestamp.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha;session";
message Session {
string id = 1;
zitadel.user.v2alpha.User user = 2;
string id = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"id of the session\"";
}
];
google.protobuf.Timestamp creation_date = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"time when the session was created\"";
}
];
google.protobuf.Timestamp change_date = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"time when the session was last updated\"";
}
];
uint64 sequence = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"sequence of the session\"";
}
];
Factors factors = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"checked factors of the session, e.g. the user, password and more\"";
}
];
map<string, bytes> metadata = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"custom key value list\"";
}
];
}
message Factors {
UserFactor user = 1;
PasswordFactor password = 2;
}
message UserFactor {
google.protobuf.Timestamp verified_at = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"time when the user was last checked\"";
}
];
string id = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"id of the checked user\"";
}
];
string login_name = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"login name of the checked user\"";
}
];
string display_name = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"display name of the checked user\"";
}
];
}
message PasswordFactor {
google.protobuf.Timestamp verified_at = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"time when the password was last checked\"";
}
];
}
message SearchQuery {
oneof query {
option (validate.required) = true;
IDsQuery ids_query = 1;
}
}
message IDsQuery {
repeated string ids = 1;
}

View File

@@ -3,21 +3,82 @@ syntax = "proto3";
package zitadel.session.v2alpha;
import "zitadel/object/v2alpha/object.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto";
import "zitadel/session/v2alpha/session.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha;session";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
title: "Session Service";
version: "2.0-alpha";
description: "This API is intended to manage sessions in a ZITADEL instance. This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.";
contact:{
name: "ZITADEL"
url: "https://zitadel.com"
email: "hi@zitadel.com"
}
license: {
name: "Apache 2.0",
url: "https://github.com/zitadel/zitadel/blob/main/LICENSE";
};
};
schemes: HTTPS;
schemes: HTTP;
consumes: "application/json";
consumes: "application/grpc";
produces: "application/json";
produces: "application/grpc";
consumes: "application/grpc-web+proto";
produces: "application/grpc-web+proto";
host: "$ZITADEL_DOMAIN";
base_path: "/";
external_docs: {
description: "Detailed information about ZITADEL",
url: "https://zitadel.com/docs"
}
responses: {
key: "403";
value: {
description: "Returned when the user does not have permission to access the resource.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
}
}
}
}
responses: {
key: "404";
value: {
description: "Returned when the resource does not exist.";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
}
}
}
}
};
service SessionService {
// GetSession is to demonstrate an authenticated request, where the authenticated user (usage of another grpc package) is returned
//
// this request is subject to change and currently used for demonstration only
rpc GetSession (GetSessionRequest) returns (GetSessionResponse) {
// Search sessions
rpc ListSessions (ListSessionsRequest) returns (ListSessionsResponse) {
option (google.api.http) = {
get: "/v2alpha/sessions/{id}"
post: "/v2alpha/sessions/_search"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
@@ -25,12 +86,280 @@ service SessionService {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Search sessions";
description: "Search for sessions"
responses: {
key: "200"
value: {
description: "OK";
}
};
responses: {
key: "400";
value: {
description: "invalid list query";
schema: {
json_schema: {
ref: "#/definitions/rpcStatus";
};
};
};
};
};
}
// GetSession a session
rpc GetSession (GetSessionRequest) returns (GetSessionResponse) {
option (google.api.http) = {
get: "/v2alpha/sessions/{session_id}"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Get a session";
description: "Get a session and all its information like the time of the user or password verification"
responses: {
key: "200"
value: {
description: "OK";
}
};
};
}
// Create a new session
rpc CreateSession (CreateSessionRequest) returns (CreateSessionResponse) {
option (google.api.http) = {
post: "/v2alpha/sessions"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
http_response: {
success_code: 201
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Create a new session";
description: "Create a new session. A token will be returned, which is required for further updates of the session."
responses: {
key: "200"
value: {
description: "OK";
}
};
};
}
// Update a session
rpc SetSession (SetSessionRequest) returns (SetSessionResponse) {
option (google.api.http) = {
patch: "/v2alpha/sessions/{session_id}"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Update an existing session";
description: "Update an existing session with new information."
responses: {
key: "200"
value: {
description: "OK";
}
};
};
}
// Terminate a session
rpc DeleteSession (DeleteSessionRequest) returns (DeleteSessionResponse) {
option (google.api.http) = {
delete: "/v2alpha/sessions/{session_id}"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Terminate an existing session";
description: "Terminate your own session or if granted any other session."
responses: {
key: "200"
value: {
description: "OK";
}
};
};
}
}
message ListSessionsRequest{
zitadel.object.v2alpha.ListQuery query = 1;
repeated SearchQuery queries = 2;
}
message ListSessionsResponse{
zitadel.object.v2alpha.ListDetails details = 1;
repeated Session sessions = 2;
}
message GetSessionRequest{
string id = 1;
string session_id = 1;
optional string session_token = 2;
}
message GetSessionResponse{
Session session = 1;
}
message CreateSessionRequest{
Checks checks = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"Check for user and password. Successful checks will be stated as factors on the session.\"";
}
];
map<string, bytes> metadata = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"custom key value list to be stored on the session\"";
}
];
}
message CreateSessionResponse{
zitadel.object.v2alpha.Details details = 1;
string session_id = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"id of the session\"";
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
}
];
string session_token = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"token of the session, which is required for further updates of the session or the request other resources\"";
}
];
}
message SetSessionRequest{
string session_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
description: "\"id of the session to update\"";
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
}
];
string session_token = 2 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
description: "\"token of the session, previously returned on the create / update request\"";
}
];
Checks checks = 3[
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"Check for user and password. Successful checks will be stated as factors on the session.\"";
}
];
map<string, bytes> metadata = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"custom key value list to be stored on the session\"";
}
];
}
message SetSessionResponse{
zitadel.object.v2alpha.Details details = 1;
string session_token = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"token of the session, which is required for further updates of the session or the request other resources\"";
}
];
}
message DeleteSessionRequest{
string session_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
description: "\"id of the session to terminate\"";
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
}
];
optional string session_token = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"token of the session, previously returned on the create / update request\"";
}
];
}
message DeleteSessionResponse{
zitadel.object.v2alpha.Details details = 1;
}
message Checks {
optional CheckUser user = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"checks the user and updates the session on success\"";
}
];
optional CheckPassword password = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"Checks the password and updates the session on success. Requires that the user is already checked, either in the previous or the same request.\"";
}
];
}
message CheckUser {
oneof search {
string user_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
}
];
string login_name = 2 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"mini@mouse.com\"";
}
];
}
}
message CheckPassword {
string password = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"V3ryS3cure!\"";
}
];
}