Fully Working OAuth2Flow

This commit is contained in:
mr
2026-03-06 10:20:35 +01:00
parent 979747e288
commit 744caf9a5e
6 changed files with 120 additions and 46 deletions

View File

@@ -14,6 +14,7 @@ import (
"time" "time"
oclib "cloud.o-forge.io/core/oc-lib" oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/dbs"
"cloud.o-forge.io/core/oc-lib/models/peer" "cloud.o-forge.io/core/oc-lib/models/peer"
model "cloud.o-forge.io/core/oc-lib/models/peer" model "cloud.o-forge.io/core/oc-lib/models/peer"
beego "github.com/beego/beego/v2/server/web" beego "github.com/beego/beego/v2/server/web"
@@ -27,6 +28,8 @@ type OAuthController struct {
// @Title GetLogin // @Title GetLogin
// @Description Hydra redirects here with a login_challenge. Returns challenge info or auto-accepts if session exists. // @Description Hydra redirects here with a login_challenge. Returns challenge info or auto-accepts if session exists.
// @Param login_challenge query string true "The login challenge from Hydra" // @Param login_challenge query string true "The login challenge from Hydra"
// @Param redirect query string true "explicit redirect by passed"
// @Success 200 {object} auth_connectors.LoginChallenge // @Success 200 {object} auth_connectors.LoginChallenge
// @Failure 400 missing login_challenge // @Failure 400 missing login_challenge
// @Failure 500 internal error // @Failure 500 internal error
@@ -73,8 +76,9 @@ func (o *OAuthController) GetLogin() {
o.Data["json"] = redirect o.Data["json"] = redirect
o.ServeJSON() o.ServeJSON()
return return
}
return
}
// Return challenge info so frontend can render login form // Return challenge info so frontend can render login form
o.Data["json"] = loginChallenge o.Data["json"] = loginChallenge
o.ServeJSON() o.ServeJSON()
@@ -82,13 +86,17 @@ func (o *OAuthController) GetLogin() {
// @Title PostLogin // @Title PostLogin
// @Description Authenticate user via LDAP and accept Hydra login challenge // @Description Authenticate user via LDAP and accept Hydra login challenge
// @Param redirect query string true "explicit redirect by passed"
// @Param body body auth_connectors.LoginRequest true "Login credentials and challenge" // @Param body body auth_connectors.LoginRequest true "Login credentials and challenge"
// @Success 200 {object} auth_connectors.Redirect // @Success 200 {object} auth_connectors.Redirect
// @Failure 401 invalid credentials // @Failure 401 invalid credentials
// @Failure 500 internal error // @Failure 500 internal error
// @router /login [post] // @router /login [post]
func (o *OAuthController) Login() { func (o *OAuthController) Login() {
logger := oclib.GetLogger() logger := oclib.GetLogger()
red := o.Ctx.Input.Query("redirect")
var req auth_connectors.LoginRequest var req auth_connectors.LoginRequest
if err := json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &req); err != nil { if err := json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &req); err != nil {
o.Ctx.ResponseWriter.WriteHeader(400) o.Ctx.ResponseWriter.WriteHeader(400)
@@ -159,13 +167,18 @@ func (o *OAuthController) Login() {
} }
// Return redirect_to so the frontend follows the OAuth2 flow // Return redirect_to so the frontend follows the OAuth2 flow
if red == "false" {
o.Data["json"] = redirect o.Data["json"] = redirect
o.ServeJSON() o.ServeJSON()
return
}
o.Redirect(redirect.RedirectTo, 303)
} }
// @Title Consent // @Title Consent
// @Description Hydra redirects here with a consent_challenge. Auto-accepts consent with user permissions. // @Description Hydra redirects here with a consent_challenge. Auto-accepts consent with user permissions.
// @Param consent_challenge query string true "The consent challenge from Hydra" // @Param consent_challenge query string true "The consent challenge from Hydra"
// @Param redirect query string true "explicit redirect by passed"
// @Success 200 {object} auth_connectors.Redirect // @Success 200 {object} auth_connectors.Redirect
// @Failure 400 missing consent_challenge // @Failure 400 missing consent_challenge
// @Failure 500 internal error // @Failure 500 internal error
@@ -191,8 +204,13 @@ func (o *OAuthController) Consent() {
} }
// Get self peer for signing // Get self peer for signing
pp := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).Search( pp := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil).Search(
nil, strconv.Itoa(peer.SELF.EnumIndex()), false) &dbs.Filters{
Or: map[string][]dbs.Filter{ // search by name if no filters are provided
"relation": {{Operator: dbs.EQUAL.String(), Value: peer.SELF}},
},
}, strconv.Itoa(peer.SELF.EnumIndex()), false)
fmt.Println(pp.Err, pp.Data)
if len(pp.Data) == 0 || pp.Code >= 300 || pp.Err != "" { if len(pp.Data) == 0 || pp.Code >= 300 || pp.Err != "" {
logger.Error().Msg("Self peer not found") logger.Error().Msg("Self peer not found")
o.Ctx.ResponseWriter.WriteHeader(500) o.Ctx.ResponseWriter.WriteHeader(500)
@@ -231,12 +249,16 @@ func (o *OAuthController) Consent() {
// @Title GetLogout // @Title GetLogout
// @Description Hydra redirects here with a logout_challenge. Accepts the challenge and returns a redirect URL. // @Description Hydra redirects here with a logout_challenge. Accepts the challenge and returns a redirect URL.
// @Param logout_challenge query string true "The logout challenge from Hydra" // @Param logout_challenge query string true "The logout challenge from Hydra"
// @Param redirect query string true "explicit redirect by passed"
// @Success 200 {object} auth_connectors.Redirect // @Success 200 {object} auth_connectors.Redirect
// @Failure 400 missing logout_challenge // @Failure 400 missing logout_challenge
// @Failure 500 internal error // @Failure 500 internal error
// @router /logout [get] // @router /logout [get]
func (o *OAuthController) GetLogout() { func (o *OAuthController) GetLogout() {
logger := oclib.GetLogger() logger := oclib.GetLogger()
red := o.Ctx.Input.Query("redirect")
challenge := o.Ctx.Input.Query("logout_challenge") challenge := o.Ctx.Input.Query("logout_challenge")
if challenge == "" { if challenge == "" {
o.Ctx.ResponseWriter.WriteHeader(400) o.Ctx.ResponseWriter.WriteHeader(400)
@@ -268,15 +290,19 @@ func (o *OAuthController) GetLogout() {
o.ServeJSON() o.ServeJSON()
return return
} }
if red == "false" {
o.Data["json"] = redirect o.Data["json"] = redirect
o.ServeJSON() o.ServeJSON()
return
}
o.Redirect(redirect.RedirectTo, 303)
} }
// @Title Logout // @Title Logout
// @Description Revoke an OAuth2 token // @Description Revoke an OAuth2 token
// @Param Authorization header string false "Bearer token" // @Param Authorization header string false "Bearer token"
// @Param client_id query string true "The client_id" // @Param client_id query string true "The client_id"
// @Success 200 {object} auth_connectors.Token // @Success 200 {object} auth_connectors.Token
// @router /logout [delete] // @router /logout [delete]
func (o *OAuthController) LogOut() { func (o *OAuthController) LogOut() {

View File

@@ -14,7 +14,7 @@ services:
- "traefik.http.middlewares.auth-sec-rewrite.replacepathregex.replacement=/oc$$1" - "traefik.http.middlewares.auth-sec-rewrite.replacepathregex.replacement=/oc$$1"
- "traefik.http.services.auth-sec.loadbalancer.server.port=8080" - "traefik.http.services.auth-sec.loadbalancer.server.port=8080"
- "traefik.http.routers.auth-sec.middlewares=auth-sec-rewrite,auth-auth-sec" - "traefik.http.routers.auth-sec.middlewares=auth-sec-rewrite,auth-auth-sec"
- "traefik.http.middlewares.auth-auth-sec.forwardauth.address=http://hydra:4444/oauth2/auth" - "traefik.http.middlewares.auth-auth-sec.forwardauth.address=http://oc-auth:8080/oc/forward"
- "traefik.http.middlewares.auth-auth-sec.forwardauth.trustForwardHeader=true" - "traefik.http.middlewares.auth-auth-sec.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.auth-auth-sec.forwardauth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email" - "traefik.http.middlewares.auth-auth-sec.forwardauth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email"
environment: environment:

View File

@@ -45,8 +45,8 @@ func main() {
conf.GetConfig().Origin = o.GetStringDefault("ADMIN_ORIGIN", "http://localhost:8000") conf.GetConfig().Origin = o.GetStringDefault("ADMIN_ORIGIN", "http://localhost:8000")
conf.GetConfig().AdminOrigin = o.GetStringDefault("ADMIN_ORIGIN", "http://localhost:8001") conf.GetConfig().AdminOrigin = o.GetStringDefault("ADMIN_ORIGIN", "http://localhost:8001")
conf.GetConfig().OAuthRedirectURI = o.GetStringDefault("OAUTH_REDIRECT_URI", "http://google.com") conf.GetConfig().OAuthRedirectURI = o.GetStringDefault("OAUTH_REDIRECT_URI", "http://localhost:8000/l")
conf.GetConfig().OAdminAuthRedirectURI = o.GetStringDefault("ADMIN_OAUTH_REDIRECT_URI", "http://chatgpt.com") conf.GetConfig().OAdminAuthRedirectURI = o.GetStringDefault("ADMIN_OAUTH_REDIRECT_URI", "http://localhost:8000/l")
conf.GetConfig().Local = o.GetBoolDefault("LOCAL", true) conf.GetConfig().Local = o.GetBoolDefault("LOCAL", true)
// config LDAPauth // config LDAPauth

BIN
oc-auth

Binary file not shown.

View File

@@ -29,6 +29,13 @@
"description": "The consent challenge from Hydra", "description": "The consent challenge from Hydra",
"required": true, "required": true,
"type": "string" "type": "string"
},
{
"in": "query",
"name": "redirect",
"description": "explicit redirect by passed",
"required": true,
"type": "string"
} }
], ],
"responses": { "responses": {
@@ -282,6 +289,13 @@
"description": "The login challenge from Hydra", "description": "The login challenge from Hydra",
"required": true, "required": true,
"type": "string" "type": "string"
},
{
"in": "query",
"name": "redirect",
"description": "explicit redirect by passed",
"required": true,
"type": "string"
} }
], ],
"responses": { "responses": {
@@ -304,8 +318,15 @@
"oc-auth/controllersOAuthController" "oc-auth/controllersOAuthController"
], ],
"description": "Authenticate user via LDAP and accept Hydra login challenge\n\u003cbr\u003e", "description": "Authenticate user via LDAP and accept Hydra login challenge\n\u003cbr\u003e",
"operationId": "OAuthController.PostLogin", "operationId": "OAuthController.Login",
"parameters": [ "parameters": [
{
"in": "query",
"name": "redirect",
"description": "explicit redirect by passed",
"required": true,
"type": "string"
},
{ {
"in": "body", "in": "body",
"name": "body", "name": "body",
@@ -346,6 +367,13 @@
"description": "The logout challenge from Hydra", "description": "The logout challenge from Hydra",
"required": true, "required": true,
"type": "string" "type": "string"
},
{
"in": "query",
"name": "redirect",
"description": "explicit redirect by passed",
"required": true,
"type": "string"
} }
], ],
"responses": { "responses": {
@@ -798,14 +826,29 @@
} }
}, },
"definitions": { "definitions": {
"2432.0xc000460e70.false": { "2432.0xc0004a0630.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
"4171.0xc000461050.false": { "4171.0xc0004a0810.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
"auth_connectors.LoginRequest": {
"title": "LoginRequest",
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string"
},
"login_challenge": {
"type": "string"
}
}
},
"auth_connectors.IntrospectResult": { "auth_connectors.IntrospectResult": {
"title": "IntrospectResult", "title": "IntrospectResult",
"type": "object", "type": "object",
@@ -821,7 +864,7 @@
"format": "int64" "format": "int64"
}, },
"ext": { "ext": {
"$ref": "#/definitions/4171.0xc000461050.false" "$ref": "#/definitions/4171.0xc0004a0810.false"
}, },
"scope": { "scope": {
"type": "string" "type": "string"
@@ -842,7 +885,7 @@
"type": "string" "type": "string"
}, },
"client": { "client": {
"$ref": "#/definitions/2432.0xc000460e70.false" "$ref": "#/definitions/2432.0xc0004a0630.false"
}, },
"request_url": { "request_url": {
"type": "string" "type": "string"
@@ -858,21 +901,6 @@
} }
} }
}, },
"auth_connectors.LoginRequest": {
"title": "LoginRequest",
"type": "object",
"properties": {
"login_challenge": {
"type": "string"
},
"password": {
"type": "string"
},
"username": {
"type": "string"
}
}
},
"auth_connectors.Redirect": { "auth_connectors.Redirect": {
"title": "Redirect", "title": "Redirect",
"type": "object", "type": "object",

View File

@@ -26,6 +26,11 @@ paths:
description: The consent challenge from Hydra description: The consent challenge from Hydra
required: true required: true
type: string type: string
- in: query
name: redirect
description: explicit redirect by passed
required: true
type: string
responses: responses:
"200": "200":
description: "" description: ""
@@ -214,6 +219,11 @@ paths:
description: The login challenge from Hydra description: The login challenge from Hydra
required: true required: true
type: string type: string
- in: query
name: redirect
description: explicit redirect by passed
required: true
type: string
responses: responses:
"200": "200":
description: "" description: ""
@@ -229,8 +239,13 @@ paths:
description: |- description: |-
Authenticate user via LDAP and accept Hydra login challenge Authenticate user via LDAP and accept Hydra login challenge
<br> <br>
operationId: OAuthController.PostLogin operationId: OAuthController.Login
parameters: parameters:
- in: query
name: redirect
description: explicit redirect by passed
required: true
type: string
- in: body - in: body
name: body name: body
description: Login credentials and challenge description: Login credentials and challenge
@@ -260,6 +275,11 @@ paths:
description: The logout challenge from Hydra description: The logout challenge from Hydra
required: true required: true
type: string type: string
- in: query
name: redirect
description: explicit redirect by passed
required: true
type: string
responses: responses:
"200": "200":
description: "" description: ""
@@ -593,12 +613,22 @@ paths:
"200": "200":
description: "" description: ""
definitions: definitions:
2432.0xc000460e70.false: 2432.0xc0004a0630.false:
title: "false" title: "false"
type: object type: object
4171.0xc000461050.false: 4171.0xc0004a0810.false:
title: "false" title: "false"
type: object type: object
auth_connectors.LoginRequest:
title: LoginRequest
type: object
properties:
username:
type: string
password:
type: string
login_challenge:
type: string
auth_connectors.IntrospectResult: auth_connectors.IntrospectResult:
title: IntrospectResult title: IntrospectResult
type: object type: object
@@ -611,7 +641,7 @@ definitions:
type: integer type: integer
format: int64 format: int64
ext: ext:
$ref: '#/definitions/4171.0xc000461050.false' $ref: '#/definitions/4171.0xc0004a0810.false'
scope: scope:
type: string type: string
sub: sub:
@@ -625,7 +655,7 @@ definitions:
challenge: challenge:
type: string type: string
client: client:
$ref: '#/definitions/2432.0xc000460e70.false' $ref: '#/definitions/2432.0xc0004a0630.false'
request_url: request_url:
type: string type: string
session_id: session_id:
@@ -634,16 +664,6 @@ definitions:
type: boolean type: boolean
subject: subject:
type: string type: string
auth_connectors.LoginRequest:
title: LoginRequest
type: object
properties:
login_challenge:
type: string
password:
type: string
username:
type: string
auth_connectors.Redirect: auth_connectors.Redirect:
title: Redirect title: Redirect
type: object type: object