mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: move /gitauth to /externalauth on the frontend (#9954)
* chore: move `/gitauth` to `/externalauth` on the frontend This actually took a lot more jank than anticipated, so I wanted to split this up before adding the ability to embed new providers. * Rename FE * Fix em' up * Fix linting error * Fix e2e tests * chore: update helm golden files
This commit is contained in:
Generated
+188
-188
@@ -602,6 +602,103 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/externalauth/{externalauth}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Git"
|
||||
],
|
||||
"summary": "Get external auth by ID",
|
||||
"operationId": "get-external-auth-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "externalauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuth"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/externalauth/{externalauth}/device": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Git"
|
||||
],
|
||||
"summary": "Get external auth device by ID.",
|
||||
"operationId": "get-external-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "externalauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthDevice"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Git"
|
||||
],
|
||||
"summary": "Post external auth device by ID",
|
||||
"operationId": "post-external-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "External Provider ID",
|
||||
"name": "externalauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -677,103 +774,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/gitauth/{gitauth}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Git"
|
||||
],
|
||||
"summary": "Get git auth by ID",
|
||||
"operationId": "get-git-auth-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "gitauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.GitAuth"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/gitauth/{gitauth}/device": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Git"
|
||||
],
|
||||
"summary": "Get git auth device by ID.",
|
||||
"operationId": "get-git-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "gitauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.GitAuthDevice"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Git"
|
||||
],
|
||||
"summary": "Post git auth device by ID",
|
||||
"operationId": "post-git-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "gitauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/groups/{group}": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -2768,7 +2768,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/gitauth": {
|
||||
"/templateversions/{templateversion}/externalauth": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -2781,8 +2781,8 @@ const docTemplate = `{
|
||||
"tags": [
|
||||
"Templates"
|
||||
],
|
||||
"summary": "Get git auth by template version",
|
||||
"operationId": "get-git-auth-by-template-version",
|
||||
"summary": "Get external auth by template version",
|
||||
"operationId": "get-external-auth-by-template-version",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
@@ -8186,6 +8186,77 @@ const docTemplate = `{
|
||||
"ExperimentDeploymentHealthPage"
|
||||
]
|
||||
},
|
||||
"codersdk.ExternalAuth": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"app_install_url": {
|
||||
"description": "AppInstallURL is the URL to install the app.",
|
||||
"type": "string"
|
||||
},
|
||||
"app_installable": {
|
||||
"description": "AppInstallable is true if the request for app installs was successful.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"authenticated": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"device": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"installations": {
|
||||
"description": "AppInstallations are the installations that the user has access to.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthAppInstallation"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"description": "User is the user that authenticated with the provider.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthUser"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ExternalAuthAppInstallation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"account": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthUser"
|
||||
},
|
||||
"configure_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ExternalAuthDevice": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_in": {
|
||||
"type": "integer"
|
||||
},
|
||||
"interval": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"verification_uri": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ExternalAuthProvider": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -8203,6 +8274,23 @@ const docTemplate = `{
|
||||
"ExternalAuthProviderOpenIDConnect"
|
||||
]
|
||||
},
|
||||
"codersdk.ExternalAuthUser": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.Feature": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8242,57 +8330,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuth": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"app_install_url": {
|
||||
"description": "AppInstallURL is the URL to install the app.",
|
||||
"type": "string"
|
||||
},
|
||||
"app_installable": {
|
||||
"description": "AppInstallable is true if the request for app installs was successful.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"authenticated": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"device": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"installations": {
|
||||
"description": "AppInstallations are the installations that the user has access to.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.GitAuthAppInstallation"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"description": "User is the user that authenticated with the provider.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.GitAuthUser"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthAppInstallation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"account": {
|
||||
"$ref": "#/definitions/codersdk.GitAuthUser"
|
||||
},
|
||||
"configure_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8340,43 +8377,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthDevice": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_in": {
|
||||
"type": "integer"
|
||||
},
|
||||
"interval": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"verification_uri": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthUser": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitSSHKey": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Generated
+178
-178
@@ -512,6 +512,93 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/externalauth/{externalauth}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Git"],
|
||||
"summary": "Get external auth by ID",
|
||||
"operationId": "get-external-auth-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "externalauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuth"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/externalauth/{externalauth}/device": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Git"],
|
||||
"summary": "Get external auth device by ID.",
|
||||
"operationId": "get-external-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "externalauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthDevice"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Git"],
|
||||
"summary": "Post external auth device by ID",
|
||||
"operationId": "post-external-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "External Provider ID",
|
||||
"name": "externalauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -579,93 +666,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/gitauth/{gitauth}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Git"],
|
||||
"summary": "Get git auth by ID",
|
||||
"operationId": "get-git-auth-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "gitauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.GitAuth"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/gitauth/{gitauth}/device": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Git"],
|
||||
"summary": "Get git auth device by ID.",
|
||||
"operationId": "get-git-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "gitauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.GitAuthDevice"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"tags": ["Git"],
|
||||
"summary": "Post git auth device by ID",
|
||||
"operationId": "post-git-auth-device-by-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "Git Provider ID",
|
||||
"name": "gitauth",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/groups/{group}": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -2430,7 +2430,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/gitauth": {
|
||||
"/templateversions/{templateversion}/externalauth": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -2439,8 +2439,8 @@
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Templates"],
|
||||
"summary": "Get git auth by template version",
|
||||
"operationId": "get-git-auth-by-template-version",
|
||||
"summary": "Get external auth by template version",
|
||||
"operationId": "get-external-auth-by-template-version",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
@@ -7334,6 +7334,77 @@
|
||||
"ExperimentDeploymentHealthPage"
|
||||
]
|
||||
},
|
||||
"codersdk.ExternalAuth": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"app_install_url": {
|
||||
"description": "AppInstallURL is the URL to install the app.",
|
||||
"type": "string"
|
||||
},
|
||||
"app_installable": {
|
||||
"description": "AppInstallable is true if the request for app installs was successful.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"authenticated": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"device": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"installations": {
|
||||
"description": "AppInstallations are the installations that the user has access to.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthAppInstallation"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"description": "User is the user that authenticated with the provider.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthUser"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ExternalAuthAppInstallation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"account": {
|
||||
"$ref": "#/definitions/codersdk.ExternalAuthUser"
|
||||
},
|
||||
"configure_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ExternalAuthDevice": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_in": {
|
||||
"type": "integer"
|
||||
},
|
||||
"interval": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"verification_uri": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ExternalAuthProvider": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -7351,6 +7422,23 @@
|
||||
"ExternalAuthProviderOpenIDConnect"
|
||||
]
|
||||
},
|
||||
"codersdk.ExternalAuthUser": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.Feature": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7390,57 +7478,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuth": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"app_install_url": {
|
||||
"description": "AppInstallURL is the URL to install the app.",
|
||||
"type": "string"
|
||||
},
|
||||
"app_installable": {
|
||||
"description": "AppInstallable is true if the request for app installs was successful.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"authenticated": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"device": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"installations": {
|
||||
"description": "AppInstallations are the installations that the user has access to.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.GitAuthAppInstallation"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"description": "User is the user that authenticated with the provider.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.GitAuthUser"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthAppInstallation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"account": {
|
||||
"$ref": "#/definitions/codersdk.GitAuthUser"
|
||||
},
|
||||
"configure_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7488,43 +7525,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthDevice": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_in": {
|
||||
"type": "integer"
|
||||
},
|
||||
"interval": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"verification_uri": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitAuthUser": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.GitSSHKey": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
+25
-22
@@ -37,6 +37,7 @@ import (
|
||||
|
||||
// Used for swagger docs.
|
||||
_ "github.com/coder/coder/v2/coderd/apidoc"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/v2/buildinfo"
|
||||
@@ -47,7 +48,6 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/pubsub"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/gitsshkey"
|
||||
"github.com/coder/coder/v2/coderd/healthcheck"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
@@ -115,7 +115,7 @@ type Options struct {
|
||||
SSHKeygenAlgorithm gitsshkey.Algorithm
|
||||
Telemetry telemetry.Reporter
|
||||
TracerProvider trace.TracerProvider
|
||||
ExternalAuthConfigs []*gitauth.Config
|
||||
ExternalAuthConfigs []*externalauth.Config
|
||||
RealIPConfig *httpmw.RealIPConfig
|
||||
TrialGenerator func(ctx context.Context, email string) error
|
||||
// TLSCertificates is used to mesh DERP servers securely.
|
||||
@@ -546,21 +546,24 @@ func New(options *Options) *API {
|
||||
})
|
||||
|
||||
// Register callback handlers for each OAuth2 provider.
|
||||
r.Route("/gitauth", func(r chi.Router) {
|
||||
for _, gitAuthConfig := range options.ExternalAuthConfigs {
|
||||
// We don't need to register a callback handler for device auth.
|
||||
if gitAuthConfig.DeviceAuth != nil {
|
||||
continue
|
||||
// We must support gitauth and externalauth for backwards compatibility.
|
||||
for _, route := range []string{"gitauth", "externalauth"} {
|
||||
r.Route("/"+route, func(r chi.Router) {
|
||||
for _, externalAuthConfig := range options.ExternalAuthConfigs {
|
||||
// We don't need to register a callback handler for device auth.
|
||||
if externalAuthConfig.DeviceAuth != nil {
|
||||
continue
|
||||
}
|
||||
r.Route(fmt.Sprintf("/%s/callback", externalAuthConfig.ID), func(r chi.Router) {
|
||||
r.Use(
|
||||
apiKeyMiddlewareRedirect,
|
||||
httpmw.ExtractOAuth2(externalAuthConfig, options.HTTPClient, nil),
|
||||
)
|
||||
r.Get("/", api.externalAuthCallback(externalAuthConfig))
|
||||
})
|
||||
}
|
||||
r.Route(fmt.Sprintf("/%s/callback", gitAuthConfig.ID), func(r chi.Router) {
|
||||
r.Use(
|
||||
apiKeyMiddlewareRedirect,
|
||||
httpmw.ExtractOAuth2(gitAuthConfig, options.HTTPClient, nil),
|
||||
)
|
||||
r.Get("/", api.gitAuthCallback(gitAuthConfig))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
r.Route("/api/v2", func(r chi.Router) {
|
||||
api.APIHandler = r
|
||||
@@ -613,14 +616,14 @@ func New(options *Options) *API {
|
||||
r.Get("/{fileID}", api.fileByID)
|
||||
r.Post("/", api.postFile)
|
||||
})
|
||||
r.Route("/gitauth/{gitauth}", func(r chi.Router) {
|
||||
r.Route("/externalauth/{externalauth}", func(r chi.Router) {
|
||||
r.Use(
|
||||
apiKeyMiddleware,
|
||||
httpmw.ExtractGitAuthParam(options.ExternalAuthConfigs),
|
||||
httpmw.ExtractExternalAuthParam(options.ExternalAuthConfigs),
|
||||
)
|
||||
r.Get("/", api.gitAuthByID)
|
||||
r.Post("/device", api.postGitAuthDeviceByID)
|
||||
r.Get("/device", api.gitAuthDeviceByID)
|
||||
r.Get("/", api.externalAuthByID)
|
||||
r.Post("/device", api.postExternalAuthDeviceByID)
|
||||
r.Get("/device", api.externalAuthDeviceByID)
|
||||
})
|
||||
r.Route("/organizations", func(r chi.Router) {
|
||||
r.Use(
|
||||
@@ -686,7 +689,7 @@ func New(options *Options) *API {
|
||||
r.Get("/schema", templateVersionSchemaDeprecated)
|
||||
r.Get("/parameters", templateVersionParametersDeprecated)
|
||||
r.Get("/rich-parameters", api.templateVersionRichParameters)
|
||||
r.Get("/gitauth", api.templateVersionGitAuth)
|
||||
r.Get("/externalauth", api.templateVersionExternalAuth)
|
||||
r.Get("/variables", api.templateVersionVariables)
|
||||
r.Get("/resources", api.templateVersionResources)
|
||||
r.Get("/logs", api.templateVersionLogs)
|
||||
|
||||
@@ -59,7 +59,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||
"github.com/coder/coder/v2/coderd/database/pubsub"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/gitsshkey"
|
||||
"github.com/coder/coder/v2/coderd/healthcheck"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
@@ -105,7 +105,7 @@ type Options struct {
|
||||
AutobuildStats chan<- autobuild.Stats
|
||||
Auditor audit.Auditor
|
||||
TLSCertificates []tls.Certificate
|
||||
ExternalAuthConfigs []*gitauth.Config
|
||||
ExternalAuthConfigs []*externalauth.Config
|
||||
TrialGenerator func(context.Context, string) error
|
||||
TemplateScheduleStore schedule.TemplateScheduleStore
|
||||
Coordinator tailnet.Coordinator
|
||||
@@ -899,14 +899,14 @@ func MustWorkspace(t *testing.T, client *codersdk.Client, workspaceID uuid.UUID)
|
||||
return ws
|
||||
}
|
||||
|
||||
// RequestGitAuthCallback makes a request with the proper OAuth2 state cookie
|
||||
// to the git auth callback endpoint.
|
||||
func RequestGitAuthCallback(t *testing.T, providerID string, client *codersdk.Client) *http.Response {
|
||||
// RequestExternalAuthCallback makes a request with the proper OAuth2 state cookie
|
||||
// to the external auth callback endpoint.
|
||||
func RequestExternalAuthCallback(t *testing.T, providerID string, client *codersdk.Client) *http.Response {
|
||||
client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
state := "somestate"
|
||||
oauthURL, err := client.URL.Parse(fmt.Sprintf("/gitauth/%s/callback?code=asd&state=%s", providerID, state))
|
||||
oauthURL, err := client.URL.Parse(fmt.Sprintf("/externalauth/%s/callback?code=asd&state=%s", providerID, state))
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequestWithContext(context.Background(), "GET", oauthURL.String(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -2486,7 +2486,7 @@ func (q *querier) UpdateTemplateVersionDescriptionByJobID(ctx context.Context, a
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context.Context, arg database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams) error {
|
||||
// An actor is allowed to update the template version git auth providers if they are authorized to update the template.
|
||||
// An actor is allowed to update the template version external auth providers if they are authorized to update the template.
|
||||
tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -10,31 +10,31 @@ import (
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
// @Summary Get git auth by ID
|
||||
// @ID get-git-auth-by-id
|
||||
// @Summary Get external auth by ID
|
||||
// @ID get-external-auth-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Git
|
||||
// @Param gitauth path string true "Git Provider ID" format(string)
|
||||
// @Success 200 {object} codersdk.GitAuth
|
||||
// @Router /gitauth/{gitauth} [get]
|
||||
func (api *API) gitAuthByID(w http.ResponseWriter, r *http.Request) {
|
||||
config := httpmw.GitAuthParam(r)
|
||||
// @Param externalauth path string true "Git Provider ID" format(string)
|
||||
// @Success 200 {object} codersdk.ExternalAuth
|
||||
// @Router /externalauth/{externalauth} [get]
|
||||
func (api *API) externalAuthByID(w http.ResponseWriter, r *http.Request) {
|
||||
config := httpmw.ExternalAuthParam(r)
|
||||
apiKey := httpmw.APIKey(r)
|
||||
ctx := r.Context()
|
||||
|
||||
res := codersdk.GitAuth{
|
||||
res := codersdk.ExternalAuth{
|
||||
Authenticated: false,
|
||||
Device: config.DeviceAuth != nil,
|
||||
AppInstallURL: config.AppInstallURL,
|
||||
Type: config.Type.Pretty(),
|
||||
AppInstallations: []codersdk.GitAuthAppInstallation{},
|
||||
AppInstallations: []codersdk.ExternalAuthAppInstallation{},
|
||||
}
|
||||
|
||||
link, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
|
||||
@@ -44,7 +44,7 @@ func (api *API) gitAuthByID(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.Write(ctx, w, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to get git auth link.",
|
||||
Message: "Failed to get external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -71,24 +71,24 @@ func (api *API) gitAuthByID(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
if res.AppInstallations == nil {
|
||||
res.AppInstallations = []codersdk.GitAuthAppInstallation{}
|
||||
res.AppInstallations = []codersdk.ExternalAuthAppInstallation{}
|
||||
}
|
||||
httpapi.Write(ctx, w, http.StatusOK, res)
|
||||
}
|
||||
|
||||
// @Summary Post git auth device by ID
|
||||
// @ID post-git-auth-device-by-id
|
||||
// @Summary Post external auth device by ID
|
||||
// @ID post-external-auth-device-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Tags Git
|
||||
// @Param gitauth path string true "Git Provider ID" format(string)
|
||||
// @Param externalauth path string true "External Provider ID" format(string)
|
||||
// @Success 204
|
||||
// @Router /gitauth/{gitauth}/device [post]
|
||||
func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
// @Router /externalauth/{externalauth}/device [post]
|
||||
func (api *API) postExternalAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
apiKey := httpmw.APIKey(r)
|
||||
config := httpmw.GitAuthParam(r)
|
||||
config := httpmw.ExternalAuthParam(r)
|
||||
|
||||
var req codersdk.GitAuthDeviceExchange
|
||||
var req codersdk.ExternalAuthDeviceExchange
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
return
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to get git auth link.",
|
||||
Message: "Failed to get external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -133,7 +133,7 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to insert git auth link.",
|
||||
Message: "Failed to insert external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -149,7 +149,7 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to update git auth link.",
|
||||
Message: "Failed to update external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -158,16 +158,16 @@ func (api *API) postGitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
// @Summary Get git auth device by ID.
|
||||
// @ID get-git-auth-device-by-id
|
||||
// @Summary Get external auth device by ID.
|
||||
// @ID get-external-auth-device-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Git
|
||||
// @Param gitauth path string true "Git Provider ID" format(string)
|
||||
// @Success 200 {object} codersdk.GitAuthDevice
|
||||
// @Router /gitauth/{gitauth}/device [get]
|
||||
func (*API) gitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
config := httpmw.GitAuthParam(r)
|
||||
// @Param externalauth path string true "Git Provider ID" format(string)
|
||||
// @Success 200 {object} codersdk.ExternalAuthDevice
|
||||
// @Router /externalauth/{externalauth}/device [get]
|
||||
func (*API) externalAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
config := httpmw.ExternalAuthParam(r)
|
||||
ctx := r.Context()
|
||||
|
||||
if config.DeviceAuth == nil {
|
||||
@@ -189,7 +189,7 @@ func (*API) gitAuthDeviceByID(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, http.StatusOK, deviceAuth)
|
||||
}
|
||||
|
||||
func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc {
|
||||
func (api *API) externalAuthCallback(externalAuthConfig *externalauth.Config) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
@@ -198,20 +198,20 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc
|
||||
)
|
||||
|
||||
_, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
|
||||
ProviderID: gitAuthConfig.ID,
|
||||
ProviderID: externalAuthConfig.ID,
|
||||
UserID: apiKey.UserID,
|
||||
})
|
||||
if err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to get git auth link.",
|
||||
Message: "Failed to get external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = api.Database.InsertExternalAuthLink(ctx, database.InsertExternalAuthLinkParams{
|
||||
ProviderID: gitAuthConfig.ID,
|
||||
ProviderID: externalAuthConfig.ID,
|
||||
UserID: apiKey.UserID,
|
||||
CreatedAt: dbtime.Now(),
|
||||
UpdatedAt: dbtime.Now(),
|
||||
@@ -221,14 +221,14 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to insert git auth link.",
|
||||
Message: "Failed to insert external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err = api.Database.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{
|
||||
ProviderID: gitAuthConfig.ID,
|
||||
ProviderID: externalAuthConfig.ID,
|
||||
UserID: apiKey.UserID,
|
||||
UpdatedAt: dbtime.Now(),
|
||||
OAuthAccessToken: state.Token.AccessToken,
|
||||
@@ -237,7 +237,7 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to update git auth link.",
|
||||
Message: "Failed to update external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -247,7 +247,7 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc
|
||||
redirect := state.Redirect
|
||||
if redirect == "" {
|
||||
// This is a nicely rendered screen on the frontend
|
||||
redirect = fmt.Sprintf("/gitauth/%s", gitAuthConfig.ID)
|
||||
redirect = fmt.Sprintf("/externalauth/%s", externalAuthConfig.ID)
|
||||
}
|
||||
http.Redirect(rw, r, redirect, http.StatusTemporaryRedirect)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package gitauth
|
||||
package externalauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -65,35 +65,35 @@ type Config struct {
|
||||
|
||||
// RefreshToken automatically refreshes the token if expired and permitted.
|
||||
// It returns the token and a bool indicating if the token is valid.
|
||||
func (c *Config) RefreshToken(ctx context.Context, db database.Store, gitAuthLink database.ExternalAuthLink) (database.ExternalAuthLink, bool, error) {
|
||||
func (c *Config) RefreshToken(ctx context.Context, db database.Store, externalAuthLink database.ExternalAuthLink) (database.ExternalAuthLink, bool, error) {
|
||||
// If the token is expired and refresh is disabled, we prompt
|
||||
// the user to authenticate again.
|
||||
if c.NoRefresh &&
|
||||
// If the time is set to 0, then it should never expire.
|
||||
// This is true for github, which has no expiry.
|
||||
!gitAuthLink.OAuthExpiry.IsZero() &&
|
||||
gitAuthLink.OAuthExpiry.Before(dbtime.Now()) {
|
||||
return gitAuthLink, false, nil
|
||||
!externalAuthLink.OAuthExpiry.IsZero() &&
|
||||
externalAuthLink.OAuthExpiry.Before(dbtime.Now()) {
|
||||
return externalAuthLink, false, nil
|
||||
}
|
||||
|
||||
// This is additional defensive programming. Because TokenSource is an interface,
|
||||
// we cannot be sure that the implementation will treat an 'IsZero' time
|
||||
// as "not-expired". The default implementation does, but a custom implementation
|
||||
// might not. Removing the refreshToken will guarantee a refresh will fail.
|
||||
refreshToken := gitAuthLink.OAuthRefreshToken
|
||||
refreshToken := externalAuthLink.OAuthRefreshToken
|
||||
if c.NoRefresh {
|
||||
refreshToken = ""
|
||||
}
|
||||
|
||||
token, err := c.TokenSource(ctx, &oauth2.Token{
|
||||
AccessToken: gitAuthLink.OAuthAccessToken,
|
||||
AccessToken: externalAuthLink.OAuthAccessToken,
|
||||
RefreshToken: refreshToken,
|
||||
Expiry: gitAuthLink.OAuthExpiry,
|
||||
Expiry: externalAuthLink.OAuthExpiry,
|
||||
}).Token()
|
||||
if err != nil {
|
||||
// Even if the token fails to be obtained, we still return false because
|
||||
// we aren't trying to surface an error, we're just trying to obtain a valid token.
|
||||
return gitAuthLink, false, nil
|
||||
return externalAuthLink, false, nil
|
||||
}
|
||||
r := retry.New(50*time.Millisecond, 200*time.Millisecond)
|
||||
// See the comment below why the retry and cancel is required.
|
||||
@@ -102,7 +102,7 @@ func (c *Config) RefreshToken(ctx context.Context, db database.Store, gitAuthLin
|
||||
validate:
|
||||
valid, _, err := c.ValidateToken(ctx, token.AccessToken)
|
||||
if err != nil {
|
||||
return gitAuthLink, false, xerrors.Errorf("validate git auth token: %w", err)
|
||||
return externalAuthLink, false, xerrors.Errorf("validate external auth token: %w", err)
|
||||
}
|
||||
if !valid {
|
||||
// A customer using GitHub in Australia reported that validating immediately
|
||||
@@ -116,29 +116,29 @@ validate:
|
||||
goto validate
|
||||
}
|
||||
// The token is no longer valid!
|
||||
return gitAuthLink, false, nil
|
||||
return externalAuthLink, false, nil
|
||||
}
|
||||
|
||||
if token.AccessToken != gitAuthLink.OAuthAccessToken {
|
||||
if token.AccessToken != externalAuthLink.OAuthAccessToken {
|
||||
// Update it
|
||||
gitAuthLink, err = db.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{
|
||||
externalAuthLink, err = db.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{
|
||||
ProviderID: c.ID,
|
||||
UserID: gitAuthLink.UserID,
|
||||
UserID: externalAuthLink.UserID,
|
||||
UpdatedAt: dbtime.Now(),
|
||||
OAuthAccessToken: token.AccessToken,
|
||||
OAuthRefreshToken: token.RefreshToken,
|
||||
OAuthExpiry: token.Expiry,
|
||||
})
|
||||
if err != nil {
|
||||
return gitAuthLink, false, xerrors.Errorf("update git auth link: %w", err)
|
||||
return externalAuthLink, false, xerrors.Errorf("update external auth link: %w", err)
|
||||
}
|
||||
}
|
||||
return gitAuthLink, true, nil
|
||||
return externalAuthLink, true, nil
|
||||
}
|
||||
|
||||
// ValidateToken ensures the Git token provided is valid!
|
||||
// The user is optionally returned if the provider supports it.
|
||||
func (c *Config) ValidateToken(ctx context.Context, token string) (bool, *codersdk.GitAuthUser, error) {
|
||||
func (c *Config) ValidateToken(ctx context.Context, token string) (bool, *codersdk.ExternalAuthUser, error) {
|
||||
if c.ValidateURL == "" {
|
||||
// Default that the token is valid if no validation URL is provided.
|
||||
return true, nil, nil
|
||||
@@ -167,12 +167,12 @@ func (c *Config) ValidateToken(ctx context.Context, token string) (bool, *coders
|
||||
return false, nil, xerrors.Errorf("status %d: body: %s", res.StatusCode, data)
|
||||
}
|
||||
|
||||
var user *codersdk.GitAuthUser
|
||||
var user *codersdk.ExternalAuthUser
|
||||
if c.Type == codersdk.ExternalAuthProviderGitHub {
|
||||
var ghUser github.User
|
||||
err = json.NewDecoder(res.Body).Decode(&ghUser)
|
||||
if err == nil {
|
||||
user = &codersdk.GitAuthUser{
|
||||
user = &codersdk.ExternalAuthUser{
|
||||
Login: ghUser.GetLogin(),
|
||||
AvatarURL: ghUser.GetAvatarURL(),
|
||||
ProfileURL: ghUser.GetHTMLURL(),
|
||||
@@ -194,7 +194,7 @@ type AppInstallation struct {
|
||||
|
||||
// AppInstallations returns a list of app installations for the given token.
|
||||
// If the provider does not support app installations, it returns nil.
|
||||
func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk.GitAuthAppInstallation, bool, error) {
|
||||
func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk.ExternalAuthAppInstallation, bool, error) {
|
||||
if c.AppInstallationsURL == "" {
|
||||
return nil, false, nil
|
||||
}
|
||||
@@ -213,7 +213,7 @@ func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, false, nil
|
||||
}
|
||||
installs := []codersdk.GitAuthAppInstallation{}
|
||||
installs := []codersdk.ExternalAuthAppInstallation{}
|
||||
if c.Type == codersdk.ExternalAuthProviderGitHub {
|
||||
var ghInstalls struct {
|
||||
Installations []*github.Installation `json:"installations"`
|
||||
@@ -227,10 +227,10 @@ func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk
|
||||
if account == nil {
|
||||
continue
|
||||
}
|
||||
installs = append(installs, codersdk.GitAuthAppInstallation{
|
||||
installs = append(installs, codersdk.ExternalAuthAppInstallation{
|
||||
ID: int(installation.GetID()),
|
||||
ConfigureURL: installation.GetHTMLURL(),
|
||||
Account: codersdk.GitAuthUser{
|
||||
Account: codersdk.ExternalAuthUser{
|
||||
Login: account.GetLogin(),
|
||||
AvatarURL: account.GetAvatarURL(),
|
||||
ProfileURL: account.GetHTMLURL(),
|
||||
@@ -266,30 +266,30 @@ func ConvertConfig(entries []codersdk.GitAuthConfig, accessURL *url.URL) ([]*Con
|
||||
entry.ID = string(typ)
|
||||
}
|
||||
if valid := httpapi.NameValid(entry.ID); valid != nil {
|
||||
return nil, xerrors.Errorf("git auth provider %q doesn't have a valid id: %w", entry.ID, valid)
|
||||
return nil, xerrors.Errorf("external auth provider %q doesn't have a valid id: %w", entry.ID, valid)
|
||||
}
|
||||
|
||||
_, exists := ids[entry.ID]
|
||||
if exists {
|
||||
if entry.ID == string(typ) {
|
||||
return nil, xerrors.Errorf("multiple %s git auth providers provided. you must specify a unique id for each", typ)
|
||||
return nil, xerrors.Errorf("multiple %s external auth providers provided. you must specify a unique id for each", typ)
|
||||
}
|
||||
return nil, xerrors.Errorf("multiple git providers exist with the id %q. specify a unique id for each", entry.ID)
|
||||
}
|
||||
ids[entry.ID] = struct{}{}
|
||||
|
||||
if entry.ClientID == "" {
|
||||
return nil, xerrors.Errorf("%q git auth provider: client_id must be provided", entry.ID)
|
||||
return nil, xerrors.Errorf("%q external auth provider: client_id must be provided", entry.ID)
|
||||
}
|
||||
authRedirect, err := accessURL.Parse(fmt.Sprintf("/gitauth/%s/callback", entry.ID))
|
||||
authRedirect, err := accessURL.Parse(fmt.Sprintf("/externalauth/%s/callback", entry.ID))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse gitauth callback url: %w", err)
|
||||
return nil, xerrors.Errorf("parse externalauth callback url: %w", err)
|
||||
}
|
||||
regex := regex[typ]
|
||||
if entry.Regex != "" {
|
||||
regex, err = regexp.Compile(entry.Regex)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("compile regex for git auth provider %q: %w", entry.ID, entry.Regex)
|
||||
return nil, xerrors.Errorf("compile regex for external auth provider %q: %w", entry.ID, entry.Regex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ func ConvertConfig(entries []codersdk.GitAuthConfig, accessURL *url.URL) ([]*Con
|
||||
entry.DeviceCodeURL = deviceAuthURL[typ]
|
||||
}
|
||||
if entry.DeviceCodeURL == "" {
|
||||
return nil, xerrors.Errorf("git auth provider %q: device auth url must be provided", entry.ID)
|
||||
return nil, xerrors.Errorf("external auth provider %q: device auth url must be provided", entry.ID)
|
||||
}
|
||||
cfg.DeviceAuth = &DeviceAuth{
|
||||
ClientID: entry.ClientID,
|
||||
@@ -1,4 +1,4 @@
|
||||
package gitauth_test
|
||||
package externalauth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -19,14 +19,13 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbfake"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
func TestRefreshToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
const providerID = "test-idp"
|
||||
expired := time.Now().Add(time.Hour * -1)
|
||||
|
||||
t.Run("NoRefreshExpired", func(t *testing.T) {
|
||||
@@ -44,7 +43,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
return nil, xerrors.New("should not be called")
|
||||
}),
|
||||
},
|
||||
GitConfigOpt: func(cfg *gitauth.Config) {
|
||||
GitConfigOpt: func(cfg *externalauth.Config) {
|
||||
cfg.NoRefresh = true
|
||||
},
|
||||
})
|
||||
@@ -75,7 +74,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
return jwt.MapClaims{}, nil
|
||||
}),
|
||||
},
|
||||
GitConfigOpt: func(cfg *gitauth.Config) {
|
||||
GitConfigOpt: func(cfg *externalauth.Config) {
|
||||
cfg.NoRefresh = true
|
||||
},
|
||||
})
|
||||
@@ -92,7 +91,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
|
||||
t.Run("FalseIfTokenSourceFails", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
config := &gitauth.Config{
|
||||
config := &externalauth.Config{
|
||||
OAuth2Config: &testutil.OAuth2Config{
|
||||
TokenSourceFunc: func() (*oauth2.Token, error) {
|
||||
return nil, xerrors.New("failure")
|
||||
@@ -118,7 +117,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
return jwt.MapClaims{}, xerrors.New(staticError)
|
||||
}),
|
||||
},
|
||||
GitConfigOpt: func(cfg *gitauth.Config) {
|
||||
GitConfigOpt: func(cfg *externalauth.Config) {
|
||||
},
|
||||
})
|
||||
|
||||
@@ -143,7 +142,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
return jwt.MapClaims{}, oidctest.StatusError(http.StatusUnauthorized, xerrors.New(staticError))
|
||||
}),
|
||||
},
|
||||
GitConfigOpt: func(cfg *gitauth.Config) {
|
||||
GitConfigOpt: func(cfg *externalauth.Config) {
|
||||
},
|
||||
})
|
||||
|
||||
@@ -176,7 +175,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
return jwt.MapClaims{}, oidctest.StatusError(http.StatusUnauthorized, xerrors.New(staticError))
|
||||
}),
|
||||
},
|
||||
GitConfigOpt: func(cfg *gitauth.Config) {
|
||||
GitConfigOpt: func(cfg *externalauth.Config) {
|
||||
cfg.Type = codersdk.ExternalAuthProviderGitHub
|
||||
},
|
||||
})
|
||||
@@ -206,7 +205,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
return jwt.MapClaims{}, nil
|
||||
}),
|
||||
},
|
||||
GitConfigOpt: func(cfg *gitauth.Config) {
|
||||
GitConfigOpt: func(cfg *externalauth.Config) {
|
||||
cfg.Type = codersdk.ExternalAuthProviderGitHub
|
||||
},
|
||||
})
|
||||
@@ -237,7 +236,7 @@ func TestRefreshToken(t *testing.T) {
|
||||
return jwt.MapClaims{}, nil
|
||||
}),
|
||||
},
|
||||
GitConfigOpt: func(cfg *gitauth.Config) {
|
||||
GitConfigOpt: func(cfg *externalauth.Config) {
|
||||
cfg.Type = codersdk.ExternalAuthProviderGitHub
|
||||
},
|
||||
DB: db,
|
||||
@@ -268,7 +267,7 @@ func TestConvertYAML(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
Name string
|
||||
Input []codersdk.GitAuthConfig
|
||||
Output []*gitauth.Config
|
||||
Output []*externalauth.Config
|
||||
Error string
|
||||
}{{
|
||||
Name: "InvalidType",
|
||||
@@ -298,7 +297,7 @@ func TestConvertYAML(t *testing.T) {
|
||||
}, {
|
||||
Type: string(codersdk.ExternalAuthProviderGitHub),
|
||||
}},
|
||||
Error: "multiple github git auth providers provided",
|
||||
Error: "multiple github external auth providers provided",
|
||||
}, {
|
||||
Name: "InvalidRegex",
|
||||
Input: []codersdk.GitAuthConfig{{
|
||||
@@ -307,7 +306,7 @@ func TestConvertYAML(t *testing.T) {
|
||||
ClientSecret: "example",
|
||||
Regex: `\K`,
|
||||
}},
|
||||
Error: "compile regex for git auth provider",
|
||||
Error: "compile regex for external auth provider",
|
||||
}, {
|
||||
Name: "NoDeviceURL",
|
||||
Input: []codersdk.GitAuthConfig{{
|
||||
@@ -321,7 +320,7 @@ func TestConvertYAML(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
output, err := gitauth.ConvertConfig(tc.Input, &url.URL{})
|
||||
output, err := externalauth.ConvertConfig(tc.Input, &url.URL{})
|
||||
if tc.Error != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tc.Error)
|
||||
@@ -333,7 +332,7 @@ func TestConvertYAML(t *testing.T) {
|
||||
|
||||
t.Run("CustomScopesAndEndpoint", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
config, err := gitauth.ConvertConfig([]codersdk.GitAuthConfig{{
|
||||
config, err := externalauth.ConvertConfig([]codersdk.GitAuthConfig{{
|
||||
Type: string(codersdk.ExternalAuthProviderGitLab),
|
||||
ClientID: "id",
|
||||
ClientSecret: "secret",
|
||||
@@ -342,24 +341,24 @@ func TestConvertYAML(t *testing.T) {
|
||||
Scopes: []string{"read"},
|
||||
}}, &url.URL{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://auth.com?client_id=id&redirect_uri=%2Fgitauth%2Fgitlab%2Fcallback&response_type=code&scope=read", config[0].AuthCodeURL(""))
|
||||
require.Equal(t, "https://auth.com?client_id=id&redirect_uri=%2Fexternalauth%2Fgitlab%2Fcallback&response_type=code&scope=read", config[0].AuthCodeURL(""))
|
||||
})
|
||||
}
|
||||
|
||||
type testConfig struct {
|
||||
FakeIDPOpts []oidctest.FakeIDPOpt
|
||||
CoderOIDCConfigOpts []func(cfg *coderd.OIDCConfig)
|
||||
GitConfigOpt func(cfg *gitauth.Config)
|
||||
GitConfigOpt func(cfg *externalauth.Config)
|
||||
// If DB is passed in, the link will be inserted into the DB.
|
||||
DB database.Store
|
||||
}
|
||||
|
||||
// setupTest will configure a fake IDP and a gitauth.Config for testing.
|
||||
// setupTest will configure a fake IDP and a externalauth.Config for testing.
|
||||
// The Fake's userinfo endpoint is used for validating tokens.
|
||||
// No http servers are started so use the fake IDP's HTTPClient to make requests.
|
||||
// The returned token is a fully valid token for the IDP. Feel free to manipulate it
|
||||
// to test different scenarios.
|
||||
func setupOauth2Test(t *testing.T, settings testConfig) (*oidctest.FakeIDP, *gitauth.Config, database.ExternalAuthLink) {
|
||||
func setupOauth2Test(t *testing.T, settings testConfig) (*oidctest.FakeIDP, *externalauth.Config, database.ExternalAuthLink) {
|
||||
t.Helper()
|
||||
|
||||
const providerID = "test-idp"
|
||||
@@ -367,7 +366,7 @@ func setupOauth2Test(t *testing.T, settings testConfig) (*oidctest.FakeIDP, *git
|
||||
append([]oidctest.FakeIDPOpt{}, settings.FakeIDPOpts...)...,
|
||||
)
|
||||
|
||||
config := &gitauth.Config{
|
||||
config := &externalauth.Config{
|
||||
OAuth2Config: fake.OIDCConfig(t, nil, settings.CoderOIDCConfigOpts...),
|
||||
ID: providerID,
|
||||
ValidateURL: fake.WellknownConfig().UserInfoURL,
|
||||
@@ -1,4 +1,4 @@
|
||||
package gitauth
|
||||
package externalauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -107,7 +107,7 @@ type DeviceAuth struct {
|
||||
|
||||
// AuthorizeDevice begins the device authorization flow.
|
||||
// See: https://tools.ietf.org/html/rfc8628#section-3.1
|
||||
func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.GitAuthDevice, error) {
|
||||
func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.ExternalAuthDevice, error) {
|
||||
if c.CodeURL == "" {
|
||||
return nil, xerrors.New("oauth2: device code URL not set")
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.GitAuthDevi
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var r struct {
|
||||
codersdk.GitAuthDevice
|
||||
codersdk.ExternalAuthDevice
|
||||
ErrorDescription string `json:"error_description"`
|
||||
}
|
||||
err = json.NewDecoder(resp.Body).Decode(&r)
|
||||
@@ -136,7 +136,7 @@ func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.GitAuthDevi
|
||||
if r.ErrorDescription != "" {
|
||||
return nil, xerrors.New(r.ErrorDescription)
|
||||
}
|
||||
return &r.GitAuthDevice, nil
|
||||
return &r.ExternalAuthDevice, nil
|
||||
}
|
||||
|
||||
type ExchangeDeviceCodeResponse struct {
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/codersdk/agentsdk"
|
||||
@@ -26,19 +26,19 @@ import (
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
func TestGitAuthByID(t *testing.T) {
|
||||
func TestExternalAuthByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Unauthenticated", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "test",
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
Type: codersdk.ExternalAuthProviderGitHub,
|
||||
}},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
auth, err := client.GitAuthByID(context.Background(), "test")
|
||||
auth, err := client.ExternalAuthByID(context.Background(), "test")
|
||||
require.NoError(t, err)
|
||||
require.False(t, auth.Authenticated)
|
||||
})
|
||||
@@ -47,7 +47,7 @@ func TestGitAuthByID(t *testing.T) {
|
||||
// still return that the provider is authenticated.
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "test",
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
// AzureDevops doesn't have a user endpoint!
|
||||
@@ -55,9 +55,9 @@ func TestGitAuthByID(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "test", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "test", client)
|
||||
_ = resp.Body.Close()
|
||||
auth, err := client.GitAuthByID(context.Background(), "test")
|
||||
auth, err := client.ExternalAuthByID(context.Background(), "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, auth.Authenticated)
|
||||
})
|
||||
@@ -71,7 +71,7 @@ func TestGitAuthByID(t *testing.T) {
|
||||
}))
|
||||
defer validateSrv.Close()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "test",
|
||||
ValidateURL: validateSrv.URL,
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
@@ -79,9 +79,9 @@ func TestGitAuthByID(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "test", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "test", client)
|
||||
_ = resp.Body.Close()
|
||||
auth, err := client.GitAuthByID(context.Background(), "test")
|
||||
auth, err := client.ExternalAuthByID(context.Background(), "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, auth.Authenticated)
|
||||
require.NotNil(t, auth.User)
|
||||
@@ -111,7 +111,7 @@ func TestGitAuthByID(t *testing.T) {
|
||||
}))
|
||||
defer srv.Close()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "test",
|
||||
ValidateURL: srv.URL + "/user",
|
||||
AppInstallationsURL: srv.URL + "/installs",
|
||||
@@ -120,9 +120,9 @@ func TestGitAuthByID(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "test", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "test", client)
|
||||
_ = resp.Body.Close()
|
||||
auth, err := client.GitAuthByID(context.Background(), "test")
|
||||
auth, err := client.ExternalAuthByID(context.Background(), "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, auth.Authenticated)
|
||||
require.NotNil(t, auth.User)
|
||||
@@ -137,12 +137,12 @@ func TestGitAuthDevice(t *testing.T) {
|
||||
t.Run("NotSupported", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "test",
|
||||
}},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
_, err := client.GitAuthDeviceByID(context.Background(), "test")
|
||||
_, err := client.ExternalAuthDeviceByID(context.Background(), "test")
|
||||
var sdkErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &sdkErr)
|
||||
require.Equal(t, http.StatusBadRequest, sdkErr.StatusCode())
|
||||
@@ -150,15 +150,15 @@ func TestGitAuthDevice(t *testing.T) {
|
||||
t.Run("FetchCode", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(r.Context(), w, http.StatusOK, codersdk.GitAuthDevice{
|
||||
httpapi.Write(r.Context(), w, http.StatusOK, codersdk.ExternalAuthDevice{
|
||||
UserCode: "hey",
|
||||
})
|
||||
}))
|
||||
defer srv.Close()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "test",
|
||||
DeviceAuth: &gitauth.DeviceAuth{
|
||||
DeviceAuth: &externalauth.DeviceAuth{
|
||||
ClientID: "test",
|
||||
CodeURL: srv.URL,
|
||||
Scopes: []string{"repo"},
|
||||
@@ -166,13 +166,13 @@ func TestGitAuthDevice(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
device, err := client.GitAuthDeviceByID(context.Background(), "test")
|
||||
device, err := client.ExternalAuthDeviceByID(context.Background(), "test")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "hey", device.UserCode)
|
||||
})
|
||||
t.Run("ExchangeCode", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp := gitauth.ExchangeDeviceCodeResponse{
|
||||
resp := externalauth.ExchangeDeviceCodeResponse{
|
||||
Error: "authorization_pending",
|
||||
}
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -180,9 +180,9 @@ func TestGitAuthDevice(t *testing.T) {
|
||||
}))
|
||||
defer srv.Close()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "test",
|
||||
DeviceAuth: &gitauth.DeviceAuth{
|
||||
DeviceAuth: &externalauth.DeviceAuth{
|
||||
ClientID: "test",
|
||||
TokenURL: srv.URL,
|
||||
Scopes: []string{"repo"},
|
||||
@@ -190,7 +190,7 @@ func TestGitAuthDevice(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
err := client.GitAuthDeviceExchange(context.Background(), "test", codersdk.GitAuthDeviceExchange{
|
||||
err := client.ExternalAuthDeviceExchange(context.Background(), "test", codersdk.ExternalAuthDeviceExchange{
|
||||
DeviceCode: "hey",
|
||||
})
|
||||
var sdkErr *codersdk.Error
|
||||
@@ -198,16 +198,16 @@ func TestGitAuthDevice(t *testing.T) {
|
||||
require.Equal(t, http.StatusBadRequest, sdkErr.StatusCode())
|
||||
require.Equal(t, "authorization_pending", sdkErr.Detail)
|
||||
|
||||
resp = gitauth.ExchangeDeviceCodeResponse{
|
||||
resp = externalauth.ExchangeDeviceCodeResponse{
|
||||
AccessToken: "hey",
|
||||
}
|
||||
|
||||
err = client.GitAuthDeviceExchange(context.Background(), "test", codersdk.GitAuthDeviceExchange{
|
||||
err = client.ExternalAuthDeviceExchange(context.Background(), "test", codersdk.ExternalAuthDeviceExchange{
|
||||
DeviceCode: "hey",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
auth, err := client.GitAuthByID(context.Background(), "test")
|
||||
auth, err := client.ExternalAuthByID(context.Background(), "test")
|
||||
require.NoError(t, err)
|
||||
require.True(t, auth.Authenticated)
|
||||
})
|
||||
@@ -220,7 +220,7 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{},
|
||||
ExternalAuthConfigs: []*externalauth.Config{},
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
authToken := uuid.NewString()
|
||||
@@ -245,7 +245,7 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
ID: "github",
|
||||
Regex: regexp.MustCompile(`github\.com`),
|
||||
@@ -268,27 +268,27 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
agentClient.SetSessionToken(authToken)
|
||||
token, err := agentClient.GitAuth(context.Background(), "github.com/asd/asd", false)
|
||||
require.NoError(t, err)
|
||||
require.True(t, strings.HasSuffix(token.URL, fmt.Sprintf("/gitauth/%s", "github")))
|
||||
require.True(t, strings.HasSuffix(token.URL, fmt.Sprintf("/externalauth/%s", "github")))
|
||||
})
|
||||
t.Run("UnauthorizedCallback", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
ID: "github",
|
||||
Regex: regexp.MustCompile(`github\.com`),
|
||||
Type: codersdk.ExternalAuthProviderGitHub,
|
||||
}},
|
||||
})
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "github", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "github", client)
|
||||
require.Equal(t, http.StatusSeeOther, resp.StatusCode)
|
||||
})
|
||||
t.Run("AuthorizedCallback", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
ID: "github",
|
||||
Regex: regexp.MustCompile(`github\.com`),
|
||||
@@ -296,14 +296,14 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "github", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "github", client)
|
||||
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
location, err := resp.Location()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "/gitauth/github", location.Path)
|
||||
require.Equal(t, "/externalauth/github", location.Path)
|
||||
|
||||
// Callback again to simulate updating the token.
|
||||
resp = coderdtest.RequestGitAuthCallback(t, "github", client)
|
||||
resp = coderdtest.RequestExternalAuthCallback(t, "github", client)
|
||||
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
})
|
||||
t.Run("ValidateURL", func(t *testing.T) {
|
||||
@@ -314,7 +314,7 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
defer srv.Close()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
ValidateURL: srv.URL,
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
ID: "github",
|
||||
@@ -337,7 +337,7 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
agentClient := agentsdk.New(client.URL)
|
||||
agentClient.SetSessionToken(authToken)
|
||||
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "github", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "github", client)
|
||||
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
|
||||
// If the validation URL says unauthorized, the callback
|
||||
@@ -359,14 +359,14 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
var apiError *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiError)
|
||||
require.Equal(t, http.StatusInternalServerError, apiError.StatusCode())
|
||||
require.Equal(t, "validate git auth token: status 403: body: Something went wrong!", apiError.Detail)
|
||||
require.Equal(t, "validate external auth token: status 403: body: Something went wrong!", apiError.Detail)
|
||||
})
|
||||
|
||||
t.Run("ExpiredNoRefresh", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
OAuth2Config: &testutil.OAuth2Config{
|
||||
Token: &oauth2.Token{
|
||||
AccessToken: "token",
|
||||
@@ -402,7 +402,7 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
// In the configuration, we set our OAuth provider
|
||||
// to return an expired token. Coder consumes this
|
||||
// and stores it.
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "github", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "github", client)
|
||||
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
|
||||
// Because the token is expired and `NoRefresh` is specified,
|
||||
@@ -416,7 +416,7 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
ID: "github",
|
||||
Regex: regexp.MustCompile(`github\.com`),
|
||||
@@ -452,7 +452,7 @@ func TestGitAuthCallback(t *testing.T) {
|
||||
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "github", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "github", client)
|
||||
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
token = <-tokenChan
|
||||
require.Equal(t, "access_token", token.Username)
|
||||
@@ -1,9 +0,0 @@
|
||||
package gitauth_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOAuthJWTConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package httpmw
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
)
|
||||
|
||||
type externalAuthParamContextKey struct{}
|
||||
|
||||
func ExternalAuthParam(r *http.Request) *externalauth.Config {
|
||||
config, ok := r.Context().Value(externalAuthParamContextKey{}).(*externalauth.Config)
|
||||
if !ok {
|
||||
panic("developer error: external auth param middleware not provided")
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func ExtractExternalAuthParam(configs []*externalauth.Config) func(next http.Handler) http.Handler {
|
||||
configByID := make(map[string]*externalauth.Config)
|
||||
for _, c := range configs {
|
||||
configByID[c.ID] = c
|
||||
}
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
config, ok := configByID[chi.URLParam(r, "externalauth")]
|
||||
if !ok {
|
||||
httpapi.ResourceNotFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
r = r.WithContext(context.WithValue(r.Context(), externalAuthParamContextKey{}, config))
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -9,25 +9,25 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
)
|
||||
|
||||
//nolint:bodyclose
|
||||
func TestGitAuthParam(t *testing.T) {
|
||||
func TestExternalAuthParam(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Found", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
routeCtx := chi.NewRouteContext()
|
||||
routeCtx.URLParams.Add("gitauth", "my-id")
|
||||
routeCtx.URLParams.Add("externalauth", "my-id")
|
||||
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, routeCtx))
|
||||
res := httptest.NewRecorder()
|
||||
|
||||
httpmw.ExtractGitAuthParam([]*gitauth.Config{{
|
||||
httpmw.ExtractExternalAuthParam([]*externalauth.Config{{
|
||||
ID: "my-id",
|
||||
}})(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "my-id", httpmw.GitAuthParam(r).ID)
|
||||
require.Equal(t, "my-id", httpmw.ExternalAuthParam(r).ID)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})).ServeHTTP(res, r)
|
||||
|
||||
@@ -37,12 +37,12 @@ func TestGitAuthParam(t *testing.T) {
|
||||
t.Run("NotFound", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
routeCtx := chi.NewRouteContext()
|
||||
routeCtx.URLParams.Add("gitauth", "my-id")
|
||||
routeCtx.URLParams.Add("externalauth", "my-id")
|
||||
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, routeCtx))
|
||||
res := httptest.NewRecorder()
|
||||
|
||||
httpmw.ExtractGitAuthParam([]*gitauth.Config{})(nil).ServeHTTP(res, r)
|
||||
httpmw.ExtractExternalAuthParam([]*externalauth.Config{})(nil).ServeHTTP(res, r)
|
||||
|
||||
require.Equal(t, http.StatusNotFound, res.Result().StatusCode)
|
||||
})
|
||||
@@ -1,40 +0,0 @@
|
||||
package httpmw
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
)
|
||||
|
||||
type gitAuthParamContextKey struct{}
|
||||
|
||||
func GitAuthParam(r *http.Request) *gitauth.Config {
|
||||
config, ok := r.Context().Value(gitAuthParamContextKey{}).(*gitauth.Config)
|
||||
if !ok {
|
||||
panic("developer error: gitauth param middleware not provided")
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func ExtractGitAuthParam(configs []*gitauth.Config) func(next http.Handler) http.Handler {
|
||||
configByID := make(map[string]*gitauth.Config)
|
||||
for _, c := range configs {
|
||||
configByID[c.ID] = c
|
||||
}
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
config, ok := configByID[chi.URLParam(r, "gitauth")]
|
||||
if !ok {
|
||||
httpapi.ResourceNotFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
r = r.WithContext(context.WithValue(r.Context(), gitAuthParamContextKey{}, config))
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -65,9 +65,9 @@ func Test_RoutePatterns(t *testing.T) {
|
||||
"/api/**",
|
||||
"/@*/*/apps/**",
|
||||
"/%40*/*/apps/**",
|
||||
"/gitauth/*/callback",
|
||||
"/externalauth/*/callback",
|
||||
},
|
||||
output: "^(/api/?|/api/.+/?|/@[^/]+/[^/]+/apps/.+/?|/%40[^/]+/[^/]+/apps/.+/?|/gitauth/[^/]+/callback/?)$",
|
||||
output: "^(/api/?|/api/.+/?|/@[^/]+/[^/]+/apps/.+/?|/%40[^/]+/[^/]+/apps/.+/?|/externalauth/[^/]+/callback/?)$",
|
||||
},
|
||||
{
|
||||
name: "Slash",
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/database/pubsub"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/schedule"
|
||||
"github.com/coder/coder/v2/coderd/telemetry"
|
||||
@@ -49,7 +49,7 @@ const DefaultAcquireJobLongPollDur = time.Second * 5
|
||||
|
||||
type Options struct {
|
||||
OIDCConfig httpmw.OAuth2Config
|
||||
ExternalAuthConfigs []*gitauth.Config
|
||||
ExternalAuthConfigs []*externalauth.Config
|
||||
// TimeNowFn is only used in tests
|
||||
TimeNowFn func() time.Time
|
||||
|
||||
@@ -62,7 +62,7 @@ type server struct {
|
||||
ID uuid.UUID
|
||||
Logger slog.Logger
|
||||
Provisioners []database.ProvisionerType
|
||||
ExternalAuthConfigs []*gitauth.Config
|
||||
ExternalAuthConfigs []*externalauth.Config
|
||||
Tags Tags
|
||||
Database database.Store
|
||||
Pubsub pubsub.Pubsub
|
||||
@@ -416,7 +416,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("acquire external auth link: %s", err))
|
||||
}
|
||||
var config *gitauth.Config
|
||||
var config *externalauth.Config
|
||||
for _, c := range s.ExternalAuthConfigs {
|
||||
if c.ID != p {
|
||||
continue
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database/dbgen"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/database/pubsub"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/provisionerdserver"
|
||||
"github.com/coder/coder/v2/coderd/schedule"
|
||||
"github.com/coder/coder/v2/coderd/schedule/cron"
|
||||
@@ -143,7 +143,7 @@ func TestAcquireJob(t *testing.T) {
|
||||
gitAuthProvider := "github"
|
||||
srv, db, ps := setup(t, false, &overrides{
|
||||
deploymentValues: dv,
|
||||
externalAuthConfigs: []*gitauth.Config{{
|
||||
externalAuthConfigs: []*externalauth.Config{{
|
||||
ID: gitAuthProvider,
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
}},
|
||||
@@ -941,7 +941,7 @@ func TestCompleteJob(t *testing.T) {
|
||||
srvID := uuid.New()
|
||||
srv, db, _ := setup(t, false, &overrides{
|
||||
id: &srvID,
|
||||
externalAuthConfigs: []*gitauth.Config{{
|
||||
externalAuthConfigs: []*externalauth.Config{{
|
||||
ID: "github",
|
||||
}},
|
||||
})
|
||||
@@ -1675,7 +1675,7 @@ func TestInsertWorkspaceResource(t *testing.T) {
|
||||
|
||||
type overrides struct {
|
||||
deploymentValues *codersdk.DeploymentValues
|
||||
externalAuthConfigs []*gitauth.Config
|
||||
externalAuthConfigs []*externalauth.Config
|
||||
id *uuid.UUID
|
||||
templateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore]
|
||||
userQuietHoursScheduleStore *atomic.Pointer[schedule.UserQuietHoursScheduleStore]
|
||||
@@ -1691,7 +1691,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi
|
||||
db := dbfake.New()
|
||||
ps := pubsub.NewInMemory()
|
||||
deploymentValues := &codersdk.DeploymentValues{}
|
||||
var externalAuthConfigs []*gitauth.Config
|
||||
var externalAuthConfigs []*externalauth.Config
|
||||
srvID := uuid.New()
|
||||
tss := testTemplateScheduleStore()
|
||||
uqhss := testUserQuietHoursScheduleStore()
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/database/provisionerjobs"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/parameter"
|
||||
@@ -273,15 +273,15 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re
|
||||
httpapi.Write(ctx, rw, http.StatusOK, templateVersionParameters)
|
||||
}
|
||||
|
||||
// @Summary Get git auth by template version
|
||||
// @ID get-git-auth-by-template-version
|
||||
// @Summary Get external auth by template version
|
||||
// @ID get-external-auth-by-template-version
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Success 200 {array} codersdk.TemplateVersionExternalAuth
|
||||
// @Router /templateversions/{templateversion}/gitauth [get]
|
||||
func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request) {
|
||||
// @Router /templateversions/{templateversion}/externalauth [get]
|
||||
func (api *API) templateVersionExternalAuth(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
var (
|
||||
apiKey = httpmw.APIKey(r)
|
||||
@@ -291,7 +291,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
rawProviders := templateVersion.ExternalAuthProviders
|
||||
providers := make([]codersdk.TemplateVersionExternalAuth, 0)
|
||||
for _, rawProvider := range rawProviders {
|
||||
var config *gitauth.Config
|
||||
var config *externalauth.Config
|
||||
for _, provider := range api.ExternalAuthConfigs {
|
||||
if provider.ID == rawProvider {
|
||||
config = provider
|
||||
@@ -307,7 +307,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
// This is the URL that will redirect the user with a state token.
|
||||
redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/gitauth/%s", config.ID))
|
||||
redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/externalauth/%s", config.ID))
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to parse access URL.",
|
||||
@@ -333,7 +333,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching git auth link.",
|
||||
Message: "Internal error fetching external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -342,7 +342,7 @@ func (api *API) templateVersionGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
_, updated, err := config.RefreshToken(ctx, api.Database, authLink)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to refresh git auth token.",
|
||||
Message: "Failed to refresh external auth token.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/audit"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/provisionerdserver"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
@@ -319,7 +319,7 @@ func TestPatchCancelTemplateVersion(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestTemplateVersionsGitAuth(t *testing.T) {
|
||||
func TestTemplateVersionsExternalAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Empty", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -338,7 +338,7 @@ func TestTemplateVersionsGitAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
ExternalAuthConfigs: []*gitauth.Config{{
|
||||
ExternalAuthConfigs: []*externalauth.Config{{
|
||||
OAuth2Config: &testutil.OAuth2Config{},
|
||||
ID: "github",
|
||||
Regex: regexp.MustCompile(`github\.com`),
|
||||
@@ -351,7 +351,7 @@ func TestTemplateVersionsGitAuth(t *testing.T) {
|
||||
ProvisionPlan: []*proto.Response{{
|
||||
Type: &proto.Response_Plan{
|
||||
Plan: &proto.PlanComplete{
|
||||
GitAuthProviders: []string{"github"},
|
||||
ExternalAuthProviders: []string{"github"},
|
||||
},
|
||||
},
|
||||
}},
|
||||
@@ -368,7 +368,7 @@ func TestTemplateVersionsGitAuth(t *testing.T) {
|
||||
require.False(t, providers[0].Authenticated)
|
||||
|
||||
// Perform the Git auth callback to authenticate the user...
|
||||
resp := coderdtest.RequestGitAuthCallback(t, "github", client)
|
||||
resp := coderdtest.RequestExternalAuthCallback(t, "github", client)
|
||||
_ = resp.Body.Close()
|
||||
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ func Middleware(tracerProvider trace.TracerProvider) func(http.Handler) http.Han
|
||||
"/api/**",
|
||||
"/@*/*/apps/**",
|
||||
"/%40*/*/apps/**",
|
||||
"/gitauth/*/callback",
|
||||
"/externalauth/*/callback",
|
||||
}.MustCompile()
|
||||
|
||||
var tracer trace.Tracer
|
||||
|
||||
@@ -59,7 +59,7 @@ func Test_Middleware(t *testing.T) {
|
||||
{"/%40hi/hi/apps/hi", true},
|
||||
{"/%40hi/hi/apps/hi/hi", true},
|
||||
{"/%40hi/hi/apps/hi/hi", true},
|
||||
{"/gitauth/hi/callback", true},
|
||||
{"/externalauth/hi/callback", true},
|
||||
|
||||
// Other routes that should not be collected.
|
||||
{"/index.html", false},
|
||||
|
||||
+24
-24
@@ -34,7 +34,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/gitauth"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
@@ -2178,25 +2178,25 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
// new token to be issued!
|
||||
listen := r.URL.Query().Has("listen")
|
||||
|
||||
var gitAuthConfig *gitauth.Config
|
||||
var externalAuthConfig *externalauth.Config
|
||||
for _, gitAuth := range api.ExternalAuthConfigs {
|
||||
matches := gitAuth.Regex.MatchString(gitURL)
|
||||
if !matches {
|
||||
continue
|
||||
}
|
||||
gitAuthConfig = gitAuth
|
||||
externalAuthConfig = gitAuth
|
||||
}
|
||||
if gitAuthConfig == nil {
|
||||
detail := "No git providers are configured."
|
||||
if externalAuthConfig == nil {
|
||||
detail := "No external auth providers are configured."
|
||||
if len(api.ExternalAuthConfigs) > 0 {
|
||||
regexURLs := make([]string, 0, len(api.ExternalAuthConfigs))
|
||||
for _, gitAuth := range api.ExternalAuthConfigs {
|
||||
regexURLs = append(regexURLs, fmt.Sprintf("%s=%q", gitAuth.ID, gitAuth.Regex.String()))
|
||||
for _, extAuth := range api.ExternalAuthConfigs {
|
||||
regexURLs = append(regexURLs, fmt.Sprintf("%s=%q", extAuth.ID, extAuth.Regex.String()))
|
||||
}
|
||||
detail = fmt.Sprintf("The configured git provider have regex filters that do not match the git url. Provider url regexs: %s", strings.Join(regexURLs, ","))
|
||||
detail = fmt.Sprintf("The configured external auth provider have regex filters that do not match the git url. Provider url regexs: %s", strings.Join(regexURLs, ","))
|
||||
}
|
||||
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
|
||||
Message: fmt.Sprintf("No matching git provider found in Coder for the url %q.", gitURL),
|
||||
Message: fmt.Sprintf("No matching external auth provider found in Coder for the url %q.", gitURL),
|
||||
Detail: detail,
|
||||
})
|
||||
return
|
||||
@@ -2239,8 +2239,8 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
gitAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
|
||||
ProviderID: gitAuthConfig.ID,
|
||||
externalAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
|
||||
ProviderID: externalAuthConfig.ID,
|
||||
UserID: workspace.OwnerID,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -2248,7 +2248,7 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
continue
|
||||
}
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to get git auth link.",
|
||||
Message: "Failed to get external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -2258,27 +2258,27 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
// to expire.
|
||||
// See
|
||||
// https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app.
|
||||
if gitAuthLink.OAuthExpiry.Before(dbtime.Now()) && !gitAuthLink.OAuthExpiry.IsZero() {
|
||||
if externalAuthLink.OAuthExpiry.Before(dbtime.Now()) && !externalAuthLink.OAuthExpiry.IsZero() {
|
||||
continue
|
||||
}
|
||||
valid, _, err := gitAuthConfig.ValidateToken(ctx, gitAuthLink.OAuthAccessToken)
|
||||
valid, _, err := externalAuthConfig.ValidateToken(ctx, externalAuthLink.OAuthAccessToken)
|
||||
if err != nil {
|
||||
api.Logger.Warn(ctx, "failed to validate git auth token",
|
||||
api.Logger.Warn(ctx, "failed to validate external auth token",
|
||||
slog.F("workspace_owner_id", workspace.OwnerID.String()),
|
||||
slog.F("validate_url", gitAuthConfig.ValidateURL),
|
||||
slog.F("validate_url", externalAuthConfig.ValidateURL),
|
||||
slog.Error(err),
|
||||
)
|
||||
}
|
||||
if !valid {
|
||||
continue
|
||||
}
|
||||
httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(gitAuthConfig.Type, gitAuthLink.OAuthAccessToken))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(externalAuthConfig.Type, externalAuthLink.OAuthAccessToken))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// This is the URL that will redirect the user with a state token.
|
||||
redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/gitauth/%s", gitAuthConfig.ID))
|
||||
redirectURL, err := api.AccessURL.Parse(fmt.Sprintf("/externalauth/%s", externalAuthConfig.ID))
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to parse access URL.",
|
||||
@@ -2287,14 +2287,14 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
gitAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
|
||||
ProviderID: gitAuthConfig.ID,
|
||||
externalAuthLink, err := api.Database.GetExternalAuthLink(ctx, database.GetExternalAuthLinkParams{
|
||||
ProviderID: externalAuthConfig.ID,
|
||||
UserID: workspace.OwnerID,
|
||||
})
|
||||
if err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to get git auth link.",
|
||||
Message: "Failed to get external auth link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -2306,10 +2306,10 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
gitAuthLink, updated, err := gitAuthConfig.RefreshToken(ctx, api.Database, gitAuthLink)
|
||||
externalAuthLink, updated, err := externalAuthConfig.RefreshToken(ctx, api.Database, externalAuthLink)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to refresh git auth token.",
|
||||
Message: "Failed to refresh external auth token.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
@@ -2320,7 +2320,7 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
|
||||
})
|
||||
return
|
||||
}
|
||||
httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(gitAuthConfig.Type, gitAuthLink.OAuthAccessToken))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, formatGitAuthAccessToken(externalAuthConfig.Type, externalAuthLink.OAuthAccessToken))
|
||||
}
|
||||
|
||||
// Provider types have different username/password formats.
|
||||
|
||||
Reference in New Issue
Block a user