mirror of
https://github.com/paralus/paralus.git
synced 2026-08-24 15:47:19 +00:00
Merge pull request #4 from RafaySystems/init-saml
SAML based user authentication
This commit is contained in:
@@ -0,0 +1 @@
|
||||
APP_HOST_HTTP="http://localhost:8000"
|
||||
@@ -0,0 +1,881 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "Identity Provider (IdP) Service",
|
||||
"version": "2.0",
|
||||
"contact": {
|
||||
"name": "Rafay Dev"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "Idp"
|
||||
}
|
||||
],
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml"
|
||||
],
|
||||
"paths": {
|
||||
"/auth/v3/sso/idp": {
|
||||
"get": {
|
||||
"operationId": "Idp_ListIdps",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v3IdpList"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Returned when the user does not have permission to access the resource.",
|
||||
"schema": {}
|
||||
},
|
||||
"404": {
|
||||
"description": "Returned when the resource does not exist.",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "string"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/googlerpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Idp"
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"operationId": "Idp_CreateIdp",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v3Idp"
|
||||
}
|
||||
},
|
||||
"201": {
|
||||
"description": "Returned when idp is created successfully.",
|
||||
"schema": {}
|
||||
},
|
||||
"403": {
|
||||
"description": "Returned when the user does not have permission to access the resource.",
|
||||
"schema": {}
|
||||
},
|
||||
"404": {
|
||||
"description": "Returned when the resource does not exist.",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "string"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/googlerpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v3Idp"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Idp"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/auth/v3/sso/idp/{metadata.id}": {
|
||||
"get": {
|
||||
"operationId": "Idp_GetIdp",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v3Idp"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Returned when the user does not have permission to access the resource.",
|
||||
"schema": {}
|
||||
},
|
||||
"404": {
|
||||
"description": "Returned when the resource does not exist.",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "string"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/googlerpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "metadata.id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"description": "API Version. API Version of the idp resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"default": "usermgmt.k8smgmt.io/v3"
|
||||
},
|
||||
{
|
||||
"name": "kind",
|
||||
"description": "Kind. Kind of the idp resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"default": "Idp"
|
||||
},
|
||||
{
|
||||
"name": "metadata.name",
|
||||
"description": "Name. name of the resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.description",
|
||||
"description": "Description. description of the resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.project",
|
||||
"description": "Project. Project of the resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.organization",
|
||||
"description": "Organization. Organization to which the resource belongs",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.partner",
|
||||
"description": "Partner. Partner to which the resource belongs",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.modifiedAt",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
{
|
||||
"name": "spec.idpName",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.domain",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.acsUrl",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.ssoUrl",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.idpCert",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.spCert",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.metadataUrl",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.metadataFilename",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.saeEnabled",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "spec.groupAttributeName",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.nameIdFormat",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.consumerBinding",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.spEntityId",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "status.conditionType",
|
||||
"description": "Condition Type. type of the status condition",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "status.conditionStatus",
|
||||
"description": "Condition Status. status of the condition",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"StatusNotSet",
|
||||
"StatusSubmitted",
|
||||
"StatusOK",
|
||||
"StatusFailed"
|
||||
],
|
||||
"default": "StatusNotSet"
|
||||
},
|
||||
{
|
||||
"name": "status.lastUpdated",
|
||||
"description": "Last Updated. when the condition status is last updated",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
{
|
||||
"name": "status.reason",
|
||||
"description": "Reason. reason of the last condition status",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Idp"
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"operationId": "Idp_DeleteIdp",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"properties": {}
|
||||
}
|
||||
},
|
||||
"204": {
|
||||
"description": "Returned when idp is deleted successfully.",
|
||||
"schema": {}
|
||||
},
|
||||
"403": {
|
||||
"description": "Returned when the user does not have permission to access the resource.",
|
||||
"schema": {}
|
||||
},
|
||||
"404": {
|
||||
"description": "Returned when the resource does not exist.",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "string"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/googlerpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "metadata.id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"description": "API Version. API Version of the idp resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"default": "usermgmt.k8smgmt.io/v3"
|
||||
},
|
||||
{
|
||||
"name": "kind",
|
||||
"description": "Kind. Kind of the idp resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"default": "Idp"
|
||||
},
|
||||
{
|
||||
"name": "metadata.name",
|
||||
"description": "Name. name of the resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.description",
|
||||
"description": "Description. description of the resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.project",
|
||||
"description": "Project. Project of the resource",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.organization",
|
||||
"description": "Organization. Organization to which the resource belongs",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.partner",
|
||||
"description": "Partner. Partner to which the resource belongs",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "metadata.modifiedAt",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
{
|
||||
"name": "spec.idpName",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.domain",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.acsUrl",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.ssoUrl",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.idpCert",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.spCert",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.metadataUrl",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.metadataFilename",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.saeEnabled",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "spec.groupAttributeName",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.nameIdFormat",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.consumerBinding",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "spec.spEntityId",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "status.conditionType",
|
||||
"description": "Condition Type. type of the status condition",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "status.conditionStatus",
|
||||
"description": "Condition Status. status of the condition",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"StatusNotSet",
|
||||
"StatusSubmitted",
|
||||
"StatusOK",
|
||||
"StatusFailed"
|
||||
],
|
||||
"default": "StatusNotSet"
|
||||
},
|
||||
{
|
||||
"name": "status.lastUpdated",
|
||||
"description": "Last Updated. when the condition status is last updated",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
{
|
||||
"name": "status.reason",
|
||||
"description": "Reason. reason of the last condition status",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Idp"
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"operationId": "Idp_UpdateIdp",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v3Idp"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Returned when the user does not have permission to access the resource.",
|
||||
"schema": {}
|
||||
},
|
||||
"404": {
|
||||
"description": "Returned when the resource does not exist.",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "string"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/googlerpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "metadata.id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v3Idp"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Idp"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"commonv3Status": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"conditionType": {
|
||||
"type": "string",
|
||||
"description": "type of the status condition",
|
||||
"title": "Condition Type",
|
||||
"readOnly": true
|
||||
},
|
||||
"conditionStatus": {
|
||||
"$ref": "#/definitions/v3ConditionStatus",
|
||||
"enum": [
|
||||
"StatusNotSet",
|
||||
"StatusSubmitted",
|
||||
"StatusOK",
|
||||
"StatusFailed"
|
||||
],
|
||||
"description": "status of the condition",
|
||||
"title": "Condition Status",
|
||||
"readOnly": true
|
||||
},
|
||||
"lastUpdated": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "when the condition status is last updated",
|
||||
"title": "Last Updated",
|
||||
"readOnly": true
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"description": "reason of the last condition status",
|
||||
"title": "Reason",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"description": "status of a resource",
|
||||
"title": "Status",
|
||||
"readOnly": true
|
||||
},
|
||||
"googlerpcStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"details": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/protobufAny"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"protobufAny": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"@type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": {}
|
||||
},
|
||||
"v3ConditionStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"StatusNotSet",
|
||||
"StatusSubmitted",
|
||||
"StatusOK",
|
||||
"StatusFailed"
|
||||
],
|
||||
"default": "StatusNotSet",
|
||||
"title": "$title: ConditionStatus\n$description: status of a condition for a resource"
|
||||
},
|
||||
"v3Idp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"default": "usermgmt.k8smgmt.io/v3",
|
||||
"description": "API Version of the idp resource",
|
||||
"title": "API Version"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "Idp",
|
||||
"description": "Kind of the idp resource",
|
||||
"title": "Kind"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/definitions/v3Metadata",
|
||||
"description": "Metadata of the idp resource",
|
||||
"title": "Metadata"
|
||||
},
|
||||
"spec": {
|
||||
"$ref": "#/definitions/v3IdpSpec",
|
||||
"description": "Spec of the idp resource",
|
||||
"title": "Spec"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/definitions/commonv3Status",
|
||||
"description": "Status of the resource",
|
||||
"title": "Status",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"description": "Idp",
|
||||
"title": "Idp",
|
||||
"required": [
|
||||
"apiVersion",
|
||||
"kind",
|
||||
"metadata",
|
||||
"spec"
|
||||
]
|
||||
},
|
||||
"v3IdpList": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"default": "usermgmt.k8smgmt.io/v3",
|
||||
"description": "API Version of the idp list resource",
|
||||
"title": "API Version",
|
||||
"readOnly": true
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": "IdpList",
|
||||
"description": "Kind of the idp list resource",
|
||||
"title": "Kind",
|
||||
"readOnly": true
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/definitions/v3ListMetadata",
|
||||
"description": "Metadata of the idp list resource",
|
||||
"title": "Metadata",
|
||||
"readOnly": true
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v3Idp"
|
||||
},
|
||||
"description": "List of the idp resources",
|
||||
"title": "Items",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"description": "idp list",
|
||||
"title": "IdpList",
|
||||
"readOnly": true
|
||||
},
|
||||
"v3IdpSpec": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"idpName": {
|
||||
"type": "string"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"acsUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"ssoUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"idpCert": {
|
||||
"type": "string"
|
||||
},
|
||||
"spCert": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadataUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadataFilename": {
|
||||
"type": "string"
|
||||
},
|
||||
"saeEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"groupAttributeName": {
|
||||
"type": "string"
|
||||
},
|
||||
"nameIdFormat": {
|
||||
"type": "string"
|
||||
},
|
||||
"consumerBinding": {
|
||||
"type": "string"
|
||||
},
|
||||
"spEntityId": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v3ListMetadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
},
|
||||
"offset": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
},
|
||||
"limt": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
}
|
||||
},
|
||||
"title": "$title: ListMetadata\n$description: metadata for a list of resources\n$required: enabled"
|
||||
},
|
||||
"v3Metadata": {
|
||||
"type": "object",
|
||||
"example": {
|
||||
"name": "some-name",
|
||||
"project": "defaultproject"
|
||||
},
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "name of the resource",
|
||||
"title": "Name"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "description of the resource",
|
||||
"title": "Description"
|
||||
},
|
||||
"labels": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "labels of the resource",
|
||||
"title": "Lables"
|
||||
},
|
||||
"annotations": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "annotations of the resource",
|
||||
"title": "Annotations"
|
||||
},
|
||||
"project": {
|
||||
"type": "string",
|
||||
"description": "Project of the resource",
|
||||
"title": "Project"
|
||||
},
|
||||
"organization": {
|
||||
"type": "string",
|
||||
"description": "Organization to which the resource belongs",
|
||||
"title": "Organization"
|
||||
},
|
||||
"partner": {
|
||||
"type": "string",
|
||||
"description": "Partner to which the resource belongs",
|
||||
"title": "Partner"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"readOnly": true
|
||||
},
|
||||
"modifiedAt": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"description": "metadata of the resource",
|
||||
"title": "Metadata",
|
||||
"required": [
|
||||
"name",
|
||||
"project"
|
||||
]
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"ApiKeyAuth": {
|
||||
"type": "apiKey",
|
||||
"name": "X-RAFAY-API-KEYID",
|
||||
"in": "header"
|
||||
},
|
||||
"BasicAuth": {
|
||||
"type": "basic"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": [],
|
||||
"BasicAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "proto/types/userpb/v3/idp.proto",
|
||||
"version": "version not set"
|
||||
},
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"paths": {},
|
||||
"definitions": {
|
||||
"googlerpcStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"details": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/protobufAny"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"protobufAny": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"@type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ go 1.17
|
||||
require (
|
||||
github.com/RafaySystems/rcloud-base/components/adminsrv v0.0.0-unpublished
|
||||
github.com/RafaySystems/rcloud-base/components/common v0.0.0-unpublished
|
||||
github.com/crewjam/saml v0.4.6
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.2
|
||||
@@ -21,20 +22,27 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beevik/etree v1.1.0 // indirect
|
||||
github.com/crewjam/httperr v0.2.0 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/processout/grpc-go-pool v1.2.1 // indirect
|
||||
github.com/russellhaering/goxmldsig v1.1.1 // indirect
|
||||
github.com/segmentio/asm v1.1.0 // indirect
|
||||
github.com/segmentio/encoding v0.3.2 // indirect
|
||||
github.com/speps/go-hashids v2.0.0+incompatible // indirect
|
||||
|
||||
@@ -76,6 +76,8 @@ github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@@ -122,9 +124,14 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo=
|
||||
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
|
||||
github.com/crewjam/saml v0.4.6 h1:XCUFPkQSJLvzyl4cW9OvpWUbRf0gE7VUpU8ZnilbeM4=
|
||||
github.com/crewjam/saml v0.4.6/go.mod h1:ZBOXnNPFzB3CgOkRm7Nd6IVdkG+l/wF+0ZXLqD96t1A=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
@@ -186,6 +193,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
@@ -328,6 +337,7 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
@@ -354,6 +364,9 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -365,6 +378,8 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -407,7 +422,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
@@ -435,6 +449,7 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -474,6 +489,11 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/russellhaering/goxmldsig v1.1.1 h1:vI0r2osGF1A9PLvsGdPUAGwEIrKa4Pj5sesSBsebIxM=
|
||||
github.com/russellhaering/goxmldsig v1.1.1/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
|
||||
@@ -552,6 +572,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
@@ -609,6 +630,7 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
@@ -1057,8 +1079,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
@@ -1085,6 +1108,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -61,6 +61,7 @@ var (
|
||||
us service.UserService
|
||||
gs service.GroupService
|
||||
rs service.RoleService
|
||||
is service.IdpService
|
||||
dev bool
|
||||
_log = logv2.GetLogger()
|
||||
authPool authv3.AuthPool
|
||||
@@ -122,6 +123,7 @@ func setup() {
|
||||
us = service.NewUserService(kc, db)
|
||||
gs = service.NewGroupService(db)
|
||||
rs = service.NewRoleService(db)
|
||||
is = service.NewIdpService(db)
|
||||
|
||||
_log.Infow("usermgmt setup complete")
|
||||
}
|
||||
@@ -155,6 +157,7 @@ func runAPI(wg *sync.WaitGroup, ctx context.Context) {
|
||||
pbrpcv3.RegisterUserHandlerFromEndpoint,
|
||||
pbrpcv3.RegisterGroupHandlerFromEndpoint,
|
||||
pbrpcv3.RegisterRoleHandlerFromEndpoint,
|
||||
pbrpcv3.RegisterIdpHandlerFromEndpoint,
|
||||
)
|
||||
if err != nil {
|
||||
_log.Fatalw("unable to create gateway", "error", err)
|
||||
@@ -188,6 +191,7 @@ func runRPC(wg *sync.WaitGroup, ctx context.Context) {
|
||||
userServer := server.NewUserServer(us)
|
||||
groupServer := server.NewGroupServer(gs)
|
||||
roleServer := server.NewRoleServer(rs)
|
||||
idpServer := server.NewIdpServer(is)
|
||||
|
||||
l, err := net.Listen("tcp", fmt.Sprintf(":%d", rpcPort))
|
||||
if err != nil {
|
||||
@@ -224,6 +228,7 @@ func runRPC(wg *sync.WaitGroup, ctx context.Context) {
|
||||
rpcv3.RegisterUserServer(s, userServer)
|
||||
rpcv3.RegisterGroupServer(s, groupServer)
|
||||
rpcv3.RegisterRoleServer(s, roleServer)
|
||||
rpcv3.RegisterIdpServer(s, idpServer)
|
||||
|
||||
_log.Infow("starting rpc server", "port", rpcPort)
|
||||
err = s.Serve(l)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type Idp struct {
|
||||
bun.BaseModel `bun:"table:authsrv_idp,alias:idp"`
|
||||
|
||||
Id uuid.UUID `bun:"id,type:uuid,pk,default:uuid_generate_v4()"`
|
||||
Name string `bun:"name,notnull,unique"`
|
||||
Description string `bun:"description"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp"`
|
||||
ModifiedAt time.Time `bun:"modified_at,notnull,default:current_timestamp"`
|
||||
|
||||
IdpName string `bun:"idp_name,notnull"`
|
||||
Domain string `bun:"domain,notnull,unique"`
|
||||
AcsURL string `bun:"acs_url,notnull,unique"`
|
||||
OrganizationId uuid.UUID `bun:"organization_id,type:uuid"`
|
||||
PartnerId uuid.UUID `bun:"partner_id,type:uuid"`
|
||||
SsoURL string `bun:"sso_url"`
|
||||
IdpCert string `bun:"idp_cert"`
|
||||
SpCert string `bun:"sp_cert"`
|
||||
SpKey string `bun:"sp_key"`
|
||||
MetadataURL string `bun:"metadata_url"`
|
||||
MetadataFilename string `bun:"metadata_filename"`
|
||||
Metadata []byte `bun:"metadata"`
|
||||
GroupAttributeName string `bun:"group_attribute_name"`
|
||||
SaeEnabled bool `bun:"is_sae_enabled"`
|
||||
Trash bool `bun:"trash,default:false"`
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/usermgmt/pkg/service"
|
||||
rpcv3 "github.com/RafaySystems/rcloud-base/components/usermgmt/proto/rpc/v3"
|
||||
userv3 "github.com/RafaySystems/rcloud-base/components/usermgmt/proto/types/userpb/v3"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
type idpServer struct {
|
||||
service.IdpService
|
||||
}
|
||||
|
||||
func NewIdpServer(is service.IdpService) rpcv3.IdpServer {
|
||||
return &idpServer{is}
|
||||
}
|
||||
|
||||
func (s *idpServer) CreateIdp(ctx context.Context, idp *userv3.Idp) (*userv3.Idp, error) {
|
||||
return s.IdpService.Create(ctx, idp)
|
||||
}
|
||||
|
||||
func (s *idpServer) GetIdp(ctx context.Context, idp *userv3.Idp) (*userv3.Idp, error) {
|
||||
return s.IdpService.GetByID(ctx, idp)
|
||||
}
|
||||
|
||||
func (s *idpServer) ListIdps(ctx context.Context, _ *emptypb.Empty) (*userv3.IdpList, error) {
|
||||
return s.IdpService.List(ctx)
|
||||
}
|
||||
|
||||
func (s *idpServer) UpdateIdp(ctx context.Context, idp *userv3.Idp) (*userv3.Idp, error) {
|
||||
return s.IdpService.Update(ctx, idp)
|
||||
}
|
||||
|
||||
func (s *idpServer) DeleteIdp(ctx context.Context, idpID *userv3.Idp) (*emptypb.Empty, error) {
|
||||
return &emptypb.Empty{}, s.IdpService.Delete(ctx, idpID)
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/persistence/provider/pg"
|
||||
commonv3 "github.com/RafaySystems/rcloud-base/components/common/proto/types/commonpb/v3"
|
||||
"github.com/RafaySystems/rcloud-base/components/usermgmt/pkg/internal/models"
|
||||
userv3 "github.com/RafaySystems/rcloud-base/components/usermgmt/proto/types/userpb/v3"
|
||||
"github.com/google/uuid"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
var baseUrl *url.URL
|
||||
|
||||
func init() {
|
||||
base, ok := os.LookupEnv("APP_HOST_HTTP")
|
||||
if !ok || len(base) == 0 {
|
||||
panic("APP_HOST_HTTP env not set")
|
||||
}
|
||||
var err error
|
||||
baseUrl, err = url.Parse(base)
|
||||
if err != nil {
|
||||
panic("Failed to get application url")
|
||||
}
|
||||
}
|
||||
|
||||
type IdpService interface {
|
||||
Create(context.Context, *userv3.Idp) (*userv3.Idp, error)
|
||||
GetByID(context.Context, *userv3.Idp) (*userv3.Idp, error)
|
||||
List(context.Context) (*userv3.IdpList, error)
|
||||
Update(context.Context, *userv3.Idp) (*userv3.Idp, error)
|
||||
Delete(context.Context, *userv3.Idp) error
|
||||
}
|
||||
|
||||
type idpService struct {
|
||||
dao pg.EntityDAO
|
||||
}
|
||||
|
||||
func NewIdpService(db *bun.DB) IdpService {
|
||||
return &idpService{
|
||||
dao: pg.NewEntityDAO(db),
|
||||
}
|
||||
}
|
||||
|
||||
func generateAcsURL() (string, error) {
|
||||
uuid := uuid.New()
|
||||
return fmt.Sprintf("%s/%s/", baseUrl.String(), uuid.String()), nil
|
||||
}
|
||||
|
||||
// generateSpCert generates self signed certificate. Returns cert and
|
||||
// private key.
|
||||
func generateSpCert(host string) (string, string, error) {
|
||||
// generate private key of type rsa
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
privPEM := new(bytes.Buffer)
|
||||
err = pem.Encode(privPEM, &pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(priv),
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
privPEMBytes, err := ioutil.ReadAll(privPEM)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
template := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1000),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Rafay"},
|
||||
Country: []string{"US"},
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(30, 0, 0),
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
|
||||
DNSNames: []string{host},
|
||||
}
|
||||
// generate self sign certificate
|
||||
cBytes, err := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
cPEM := new(bytes.Buffer)
|
||||
err = pem.Encode(cPEM, &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: cBytes,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
cPEMBytes, err := ioutil.ReadAll(cPEM)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return string(cPEMBytes), string(privPEMBytes), nil
|
||||
}
|
||||
|
||||
func (s *idpService) Create(ctx context.Context, idp *userv3.Idp) (*userv3.Idp, error) {
|
||||
name := idp.Metadata.GetName()
|
||||
domain := idp.Spec.GetDomain()
|
||||
|
||||
// validate name and domain
|
||||
if len(name) == 0 {
|
||||
return &userv3.Idp{}, fmt.Errorf("EMPTY NAME")
|
||||
}
|
||||
if len(domain) == 0 {
|
||||
return &userv3.Idp{}, fmt.Errorf("EMPTY DOMAIN")
|
||||
}
|
||||
e := &models.Idp{}
|
||||
s.dao.GetByName(ctx, name, e)
|
||||
if e.Name == name {
|
||||
return &userv3.Idp{}, fmt.Errorf("DUPLICATE NAME")
|
||||
}
|
||||
s.dao.GetX(ctx, "domain", domain, e)
|
||||
if e.Domain == domain {
|
||||
return &userv3.Idp{}, fmt.Errorf("DUPLICATE DOMAIN")
|
||||
}
|
||||
|
||||
acsURL, err := generateAcsURL()
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
entity := &models.Idp{
|
||||
Name: name,
|
||||
Description: idp.Metadata.GetDescription(),
|
||||
CreatedAt: time.Now(),
|
||||
IdpName: idp.Spec.GetIdpName(),
|
||||
Domain: domain,
|
||||
AcsURL: acsURL,
|
||||
SsoURL: idp.Spec.GetSsoUrl(),
|
||||
IdpCert: idp.Spec.GetIdpCert(),
|
||||
MetadataURL: idp.Spec.GetMetadataUrl(),
|
||||
MetadataFilename: idp.Spec.GetMetadataFilename(),
|
||||
GroupAttributeName: idp.Spec.GetGroupAttributeName(),
|
||||
SaeEnabled: idp.Spec.GetSaeEnabled(),
|
||||
}
|
||||
if entity.SaeEnabled {
|
||||
spcert, spkey, err := generateSpCert(baseUrl.Host)
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
entity.SpCert = spcert
|
||||
entity.SpKey = spkey
|
||||
}
|
||||
_, err = s.dao.Create(ctx, entity)
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
|
||||
rv := &userv3.Idp{
|
||||
ApiVersion: "usermgmt.k8smgmt.io/v3",
|
||||
Kind: "Idp",
|
||||
Metadata: &commonv3.Metadata{
|
||||
Name: entity.Name,
|
||||
Organization: entity.OrganizationId.String(),
|
||||
Partner: entity.PartnerId.String(),
|
||||
Id: entity.Id.String(),
|
||||
},
|
||||
Spec: &userv3.IdpSpec{
|
||||
IdpName: entity.IdpName,
|
||||
Domain: entity.Domain,
|
||||
AcsUrl: entity.AcsURL,
|
||||
SsoUrl: entity.SsoURL,
|
||||
IdpCert: entity.IdpCert,
|
||||
SpCert: entity.SpCert,
|
||||
MetadataUrl: entity.MetadataURL,
|
||||
MetadataFilename: entity.MetadataFilename,
|
||||
SaeEnabled: entity.SaeEnabled,
|
||||
GroupAttributeName: entity.GroupAttributeName,
|
||||
NameIdFormat: "Email Address",
|
||||
ConsumerBinding: "HTTP-POST",
|
||||
SpEntityId: entity.AcsURL,
|
||||
},
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *idpService) GetByID(ctx context.Context, idp *userv3.Idp) (*userv3.Idp, error) {
|
||||
id, err := uuid.Parse(idp.Metadata.GetId())
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
entity := &models.Idp{}
|
||||
// TODO: Check for existance of id before GetByID
|
||||
_, err = s.dao.GetByID(ctx, id, entity)
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
rv := &userv3.Idp{
|
||||
ApiVersion: "usermgmt.k8smgmt.io/v3",
|
||||
Kind: "Idp",
|
||||
Metadata: &commonv3.Metadata{
|
||||
Name: entity.Name,
|
||||
Organization: entity.OrganizationId.String(),
|
||||
Partner: entity.PartnerId.String(),
|
||||
Id: entity.Id.String(),
|
||||
},
|
||||
Spec: &userv3.IdpSpec{
|
||||
IdpName: entity.IdpName,
|
||||
Domain: entity.Domain,
|
||||
AcsUrl: entity.AcsURL,
|
||||
SsoUrl: entity.SsoURL,
|
||||
IdpCert: entity.IdpCert,
|
||||
SpCert: entity.SpCert,
|
||||
MetadataUrl: entity.MetadataURL,
|
||||
MetadataFilename: entity.MetadataFilename,
|
||||
SaeEnabled: entity.SaeEnabled,
|
||||
GroupAttributeName: entity.GroupAttributeName,
|
||||
NameIdFormat: "Email Address",
|
||||
ConsumerBinding: "HTTP-POST",
|
||||
SpEntityId: entity.AcsURL,
|
||||
},
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *idpService) Update(ctx context.Context, idp *userv3.Idp) (*userv3.Idp, error) {
|
||||
var id, orgId, partId uuid.UUID
|
||||
id, err := uuid.Parse(idp.Metadata.GetId())
|
||||
// TODO: 400 Bad Request
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
if len(idp.Metadata.GetOrganization()) != 0 {
|
||||
orgId, err = uuid.Parse(idp.Metadata.GetOrganization())
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
}
|
||||
if len(idp.Metadata.GetPartner()) != 0 {
|
||||
partId, err = uuid.Parse(idp.Metadata.GetPartner())
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
}
|
||||
_, err = s.dao.GetByID(ctx, id, &models.Idp{})
|
||||
// TODO: Return proper error for Id not exist
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
|
||||
entity := &models.Idp{
|
||||
Id: id,
|
||||
Name: idp.Metadata.GetName(),
|
||||
Description: idp.Metadata.GetDescription(),
|
||||
ModifiedAt: time.Now(),
|
||||
IdpName: idp.Spec.GetIdpName(),
|
||||
Domain: idp.Spec.GetDomain(),
|
||||
AcsURL: idp.Spec.GetAcsUrl(),
|
||||
OrganizationId: orgId,
|
||||
PartnerId: partId,
|
||||
SsoURL: idp.Spec.GetSsoUrl(),
|
||||
IdpCert: idp.Spec.GetIdpCert(),
|
||||
MetadataURL: idp.Spec.GetMetadataUrl(),
|
||||
MetadataFilename: idp.Spec.GetMetadataFilename(),
|
||||
GroupAttributeName: idp.Spec.GetGroupAttributeName(),
|
||||
SaeEnabled: idp.Spec.GetSaeEnabled(),
|
||||
}
|
||||
if entity.SaeEnabled {
|
||||
spcert, spkey, err := generateSpCert(baseUrl.Host)
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
entity.SpCert = spcert
|
||||
entity.SpKey = spkey
|
||||
}
|
||||
|
||||
_, err = s.dao.Update(ctx, id, entity)
|
||||
if err != nil {
|
||||
return &userv3.Idp{}, err
|
||||
}
|
||||
rv := &userv3.Idp{
|
||||
ApiVersion: "usermgmt.k8smgmt.io/v3",
|
||||
Kind: "Idp",
|
||||
Metadata: &commonv3.Metadata{
|
||||
Name: entity.Name,
|
||||
Organization: entity.OrganizationId.String(),
|
||||
Partner: entity.PartnerId.String(),
|
||||
Id: entity.Id.String(),
|
||||
},
|
||||
Spec: &userv3.IdpSpec{
|
||||
IdpName: entity.IdpName,
|
||||
Domain: entity.Domain,
|
||||
AcsUrl: entity.AcsURL,
|
||||
SsoUrl: entity.SsoURL,
|
||||
IdpCert: entity.IdpCert,
|
||||
SpCert: entity.SpCert,
|
||||
MetadataUrl: entity.MetadataURL,
|
||||
MetadataFilename: entity.MetadataFilename,
|
||||
SaeEnabled: entity.SaeEnabled,
|
||||
GroupAttributeName: entity.GroupAttributeName,
|
||||
NameIdFormat: "Email Address",
|
||||
ConsumerBinding: "HTTP-POST",
|
||||
SpEntityId: entity.AcsURL,
|
||||
},
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *idpService) List(ctx context.Context) (*userv3.IdpList, error) {
|
||||
var (
|
||||
entities []models.Idp
|
||||
orgID uuid.NullUUID
|
||||
parID uuid.NullUUID
|
||||
)
|
||||
_, err := s.dao.List(ctx, parID, orgID, &entities)
|
||||
if err != nil {
|
||||
return &userv3.IdpList{}, err
|
||||
}
|
||||
|
||||
// Get idps only till limit
|
||||
var result []*userv3.Idp
|
||||
for _, entity := range entities {
|
||||
e := &userv3.Idp{
|
||||
ApiVersion: "usermgmt.k8smgmt.io/v3",
|
||||
Kind: "Idp",
|
||||
Metadata: &commonv3.Metadata{
|
||||
Name: entity.Name,
|
||||
Organization: entity.OrganizationId.String(),
|
||||
Partner: entity.PartnerId.String(),
|
||||
Id: entity.Id.String(),
|
||||
},
|
||||
Spec: &userv3.IdpSpec{
|
||||
IdpName: entity.IdpName,
|
||||
Domain: entity.Domain,
|
||||
AcsUrl: entity.AcsURL,
|
||||
SsoUrl: entity.SsoURL,
|
||||
IdpCert: entity.IdpCert,
|
||||
SpCert: entity.SpCert,
|
||||
MetadataUrl: entity.MetadataURL,
|
||||
MetadataFilename: entity.MetadataFilename,
|
||||
SaeEnabled: entity.SaeEnabled,
|
||||
GroupAttributeName: entity.GroupAttributeName,
|
||||
NameIdFormat: "Email Address",
|
||||
ConsumerBinding: "HTTP-POST",
|
||||
SpEntityId: entity.AcsURL,
|
||||
},
|
||||
}
|
||||
result = append(result, e)
|
||||
}
|
||||
|
||||
rv := &userv3.IdpList{
|
||||
ApiVersion: "usermgmt.k8smgmt.io/v3",
|
||||
Kind: "IdpList",
|
||||
Items: result,
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func (s *idpService) Delete(ctx context.Context, idp *userv3.Idp) error {
|
||||
id, err := uuid.Parse(idp.Metadata.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entity := &models.Idp{}
|
||||
_, err = s.dao.GetByID(ctx, id, entity)
|
||||
if entity.Id != id {
|
||||
return fmt.Errorf("ID DOES NOT EXISTS")
|
||||
}
|
||||
|
||||
err = s.dao.Delete(ctx, id, &models.Idp{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package saml
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/usermgmt/pkg/internal/models"
|
||||
"github.com/crewjam/saml"
|
||||
"github.com/crewjam/saml/samlsp"
|
||||
)
|
||||
|
||||
func newSAMLMiddlewareFromIDP(idp models.Idp) (*SAMLMiddleware, error) {
|
||||
rootURL, err := url.Parse(os.Getenv("APP_HOST_HTTP"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var idpMetadata *saml.EntityDescriptor
|
||||
if len(idp.Metadata) == 0 {
|
||||
idpMetadataURL, err := url.Parse(idp.MetadataURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idpMetadata, err = samlsp.FetchMetadata(context.Background(), http.DefaultClient,
|
||||
*idpMetadataURL)
|
||||
} else {
|
||||
idpMetadata, err = samlsp.ParseMetadata(idp.Metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
acsURL, err := url.Parse(idp.AcsURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyPair, err := tls.X509KeyPair([]byte(idp.SpCert), []byte(idp.SpKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := samlsp.Options{
|
||||
EntityID: "",
|
||||
URL: *rootURL,
|
||||
Key: keyPair.PrivateKey.(*rsa.PrivateKey),
|
||||
Certificate: keyPair.Leaf,
|
||||
AllowIDPInitiated: false,
|
||||
DefaultRedirectURI: "/prelogin",
|
||||
IDPMetadata: idpMetadata,
|
||||
SignRequest: false,
|
||||
}
|
||||
sp := samlsp.DefaultServiceProvider(opts)
|
||||
sp.AcsURL = *acsURL
|
||||
m := &samlsp.Middleware{
|
||||
ServiceProvider: sp,
|
||||
Binding: "",
|
||||
ResponseBinding: saml.HTTPPostBinding,
|
||||
OnError: samlsp.DefaultOnError,
|
||||
Session: samlsp.DefaultSessionProvider(opts),
|
||||
}
|
||||
m.RequestTracker = samlsp.DefaultRequestTracker(opts, &m.ServiceProvider)
|
||||
if opts.UseArtifactResponse {
|
||||
m.ResponseBinding = saml.HTTPArtifactBinding
|
||||
}
|
||||
return &SAMLMiddleware{m}, nil
|
||||
}
|
||||
|
||||
// SAMLAuth is an authentication middleware.
|
||||
func (s *SAMLService) SAMLAuth(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
http.Error(w, "failed to parse form data", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
username := r.PostForm.Get("username")
|
||||
|
||||
if !strings.Contains(username, "@") {
|
||||
http.Error(w, "Invalid email address", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
domain := strings.SplitN(username, "@", 2)[1]
|
||||
|
||||
entity, err := s.EntityDAO.GetX(context.Background(), "domain", domain, &models.Idp{})
|
||||
if err != nil {
|
||||
http.Error(w, "No idp found for domain", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
idp, ok := entity.(models.Idp)
|
||||
if !ok {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
m, err := newSAMLMiddlewareFromIDP(idp)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
session, err := m.Session.GetSession(r)
|
||||
if session != nil {
|
||||
r = r.WithContext(samlsp.ContextWithSession(r.Context(), session))
|
||||
w.Write([]byte("authentiated successfully"))
|
||||
return
|
||||
}
|
||||
if err == samlsp.ErrNoSession {
|
||||
m.HandleStartAuthFlow(w, r)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ServeACS performs SAML Response assertions.
|
||||
func (s *SAMLService) ServeACS(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
base, _ := url.Parse(os.Getenv("APP_HOST_HTTP"))
|
||||
acsURL := base.ResolveReference(r.URL)
|
||||
|
||||
entity, err := s.EntityDAO.GetX(context.Background(), "acs_url", acsURL.String(), &models.Idp{})
|
||||
if err != nil {
|
||||
http.Error(w, "No Idp for ACS URL", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
idp, ok := entity.(models.Idp)
|
||||
if !ok {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
m, err := newSAMLMiddlewareFromIDP(idp)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
possibleRequestIDs := []string{}
|
||||
if m.ServiceProvider.AllowIDPInitiated {
|
||||
possibleRequestIDs = append(possibleRequestIDs, "")
|
||||
}
|
||||
|
||||
trackedRequests := m.RequestTracker.GetTrackedRequests(r)
|
||||
for _, tr := range trackedRequests {
|
||||
possibleRequestIDs = append(possibleRequestIDs, tr.SAMLRequestID)
|
||||
}
|
||||
assertion, err := m.ServiceProvider.ParseResponse(r, possibleRequestIDs)
|
||||
if err != nil {
|
||||
m.OnError(w, r, err)
|
||||
return
|
||||
}
|
||||
m.CreateSessionFromAssertion(w, r, assertion, m.ServiceProvider.DefaultRedirectURI)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package saml
|
||||
|
||||
import (
|
||||
pg "github.com/RafaySystems/rcloud-base/components/common/pkg/persistence/provider/pg"
|
||||
"github.com/crewjam/saml/samlsp"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type SAMLMiddleware struct {
|
||||
*samlsp.Middleware
|
||||
}
|
||||
|
||||
type SAMLService struct {
|
||||
EntityDAO pg.EntityDAO
|
||||
}
|
||||
|
||||
func NewSAMLService(db *bun.DB) *SAMLService {
|
||||
return &SAMLService{
|
||||
EntityDAO: pg.NewEntityDAO(db),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package saml
|
||||
@@ -0,0 +1,109 @@
|
||||
syntax = "proto3";
|
||||
package rafay.dev.rpc.v3;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "proto/types/userpb/v3/idp.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||
info : {
|
||||
title : "Identity Provider (IdP) Service"
|
||||
version : "2.0"
|
||||
contact : {name : "Rafay Dev"}
|
||||
}
|
||||
schemes : HTTPS
|
||||
consumes : "application/json"
|
||||
consumes : "application/yaml"
|
||||
produces : "application/json"
|
||||
produces : "application/yaml"
|
||||
security_definitions : {
|
||||
security : {
|
||||
key : "BasicAuth"
|
||||
value : {type : TYPE_BASIC}
|
||||
}
|
||||
security : {
|
||||
key : "ApiKeyAuth"
|
||||
value : {type : TYPE_API_KEY in : IN_HEADER name : "X-RAFAY-API-KEYID"}
|
||||
}
|
||||
}
|
||||
security : {
|
||||
security_requirement : {
|
||||
key : "BasicAuth"
|
||||
value : {}
|
||||
}
|
||||
security_requirement : {
|
||||
key : "ApiKeyAuth"
|
||||
value : {}
|
||||
}
|
||||
}
|
||||
responses : {
|
||||
key : "403"
|
||||
value : {
|
||||
description : "Returned when the user does not have permission to access "
|
||||
"the resource."
|
||||
}
|
||||
}
|
||||
responses : {
|
||||
key : "404"
|
||||
value : {
|
||||
description : "Returned when the resource does not exist."
|
||||
schema : {json_schema : {type : STRING}}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
service Idp {
|
||||
rpc CreateIdp(rafay.dev.types.user.v3.Idp) returns (rafay.dev.types.user.v3.Idp) {
|
||||
option (google.api.http) = {
|
||||
post : "/auth/v3/sso/idp"
|
||||
body : "*"
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
responses : {
|
||||
key : "201"
|
||||
value : {description : "Returned when idp is created successfully."}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
rpc GetIdp(rafay.dev.types.user.v3.Idp) returns (rafay.dev.types.user.v3.Idp) {
|
||||
option (google.api.http) = {
|
||||
get : "/auth/v3/sso/idp/{metadata.id}"
|
||||
};
|
||||
};
|
||||
|
||||
rpc ListIdps(google.protobuf.Empty) returns (rafay.dev.types.user.v3.IdpList) {
|
||||
option (google.api.http) = {
|
||||
get : "/auth/v3/sso/idp"
|
||||
};
|
||||
};
|
||||
|
||||
rpc UpdateIdp(rafay.dev.types.user.v3.Idp) returns (rafay.dev.types.user.v3.Idp) {
|
||||
option (google.api.http) = {
|
||||
put : "/auth/v3/sso/idp/{metadata.id}"
|
||||
body : "*"
|
||||
};
|
||||
};
|
||||
|
||||
rpc DeleteIdp(rafay.dev.types.user.v3.Idp) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {
|
||||
delete : "/auth/v3/sso/idp/{metadata.id}"
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
responses : {
|
||||
key : "204"
|
||||
value : {
|
||||
description : "Returned when idp is deleted successfully."
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// TODO: endpooint /auth/v1/sso/idp/{id}/upload_metadata/
|
||||
// file content as request payload and response is Idp
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
syntax = "proto3";
|
||||
package rafay.dev.types.user.v3;
|
||||
|
||||
import "proto/types/commonpb/v3/common.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
|
||||
message Idp {
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
|
||||
json_schema : {
|
||||
title : "Idp"
|
||||
description : "Idp"
|
||||
required : [ "apiVersion", "kind", "metadata", "spec" ]
|
||||
}
|
||||
};
|
||||
|
||||
string apiVersion = 1
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "API Version",
|
||||
description : "API Version of the idp resource"
|
||||
default : "usermgmt.k8smgmt.io/v3"
|
||||
} ];
|
||||
string kind = 2
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Kind",
|
||||
description : "Kind of the idp resource"
|
||||
default : "Idp"
|
||||
} ];
|
||||
rafay.dev.types.common.v3.Metadata metadata = 3
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Metadata",
|
||||
description : "Metadata of the idp resource"
|
||||
} ];
|
||||
IdpSpec spec = 4
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Spec",
|
||||
description : "Spec of the idp resource"
|
||||
} ];
|
||||
|
||||
rafay.dev.types.common.v3.Status status = 5
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Status",
|
||||
description : "Status of the resource"
|
||||
read_only : true
|
||||
} ];
|
||||
}
|
||||
|
||||
message IdpSpec {
|
||||
string idpName = 1;
|
||||
string domain = 2;
|
||||
string acsUrl = 3;
|
||||
string ssoUrl = 4;
|
||||
string idpCert = 5;
|
||||
string spCert = 6;
|
||||
string metadataUrl = 7;
|
||||
string metadataFilename = 8;
|
||||
bool saeEnabled = 9;
|
||||
string groupAttributeName = 10;
|
||||
string nameIdFormat = 11;
|
||||
string consumerBinding = 12;
|
||||
string spEntityId = 13;
|
||||
}
|
||||
|
||||
message IdpList {
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
|
||||
json_schema : {
|
||||
title : "IdpList"
|
||||
description : "idp list"
|
||||
read_only : true
|
||||
}
|
||||
};
|
||||
string apiVersion = 1
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "API Version",
|
||||
description : "API Version of the idp list resource"
|
||||
default : "usermgmt.k8smgmt.io/v3"
|
||||
read_only : true
|
||||
} ];
|
||||
string kind = 2
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Kind",
|
||||
description : "Kind of the idp list resource"
|
||||
default : "IdpList"
|
||||
read_only : true
|
||||
} ];
|
||||
rafay.dev.types.common.v3.ListMetadata metadata = 3
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Metadata",
|
||||
description : "Metadata of the idp list resource"
|
||||
read_only : true
|
||||
} ];
|
||||
repeated Idp items = 4
|
||||
[ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
title : "Items",
|
||||
description : "List of the idp resources"
|
||||
read_only : true
|
||||
} ];
|
||||
}
|
||||
Reference in New Issue
Block a user