BAHAMAS
This commit is contained in:
parent
7198c40d30
commit
d87883b57f
@ -1,5 +1,8 @@
|
|||||||
FROM golang:alpine as builder
|
FROM golang:alpine as builder
|
||||||
|
|
||||||
|
ARG HOSTNAME=http://localhost
|
||||||
|
ARG NAME=local
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
Binary file not shown.
@ -3,7 +3,8 @@ package conf
|
|||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
PVKPath string
|
PublicKeyPath string
|
||||||
|
PrivateKeyPath string
|
||||||
|
|
||||||
LDAPEndpoints string
|
LDAPEndpoints string
|
||||||
LDAPBindDN string
|
LDAPBindDN string
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"oc-auth/infrastructure"
|
"oc-auth/infrastructure"
|
||||||
auth_connectors "oc-auth/infrastructure/auth_connector"
|
auth_connectors "oc-auth/infrastructure/auth_connector"
|
||||||
"oc-auth/infrastructure/claims"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
oclib "cloud.o-forge.io/core/oc-lib"
|
oclib "cloud.o-forge.io/core/oc-lib"
|
||||||
model "cloud.o-forge.io/core/oc-lib/models/peer"
|
model "cloud.o-forge.io/core/oc-lib/models/peer"
|
||||||
"cloud.o-forge.io/core/oc-lib/static"
|
|
||||||
beego "github.com/beego/beego/v2/server/web"
|
beego "github.com/beego/beego/v2/server/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -78,22 +76,6 @@ func (o *OAuthController) LoginLDAP() {
|
|||||||
o.ServeJSON()
|
o.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Title Claims
|
|
||||||
// @Description enrich token with claims
|
|
||||||
// @Param body body models.Token true "The token info"
|
|
||||||
// @Success 200 {string}
|
|
||||||
// @router /claims [post]
|
|
||||||
func (o *OAuthController) Claims() {
|
|
||||||
// enrich token with claims
|
|
||||||
var res claims.Claims
|
|
||||||
json.Unmarshal(o.Ctx.Input.CopyBody(100000), &res)
|
|
||||||
claims := res.Session.IDToken["id_token_claims"].(map[string]interface{})
|
|
||||||
userName := claims["sub"].(string)
|
|
||||||
_, loc := static.GetMyLocalJsonPeer()
|
|
||||||
o.Data["json"] = infrastructure.GetClaims().AddClaimsToToken(userName, loc["url"].(string))
|
|
||||||
o.ServeJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Title Introspection
|
// @Title Introspection
|
||||||
// @Description introspect token
|
// @Description introspect token
|
||||||
// @Param body body models.Token true "The token info"
|
// @Param body body models.Token true "The token info"
|
||||||
@ -126,6 +108,7 @@ func (o *OAuthController) Introspect() {
|
|||||||
} else {
|
} else {
|
||||||
reqToken = splitToken[1]
|
reqToken = splitToken[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := infrastructure.GetAuthConnector().Introspect(reqToken)
|
token, err := infrastructure.GetAuthConnector().Introspect(reqToken)
|
||||||
if err != nil || !token {
|
if err != nil || !token {
|
||||||
o.Data["json"] = err
|
o.Data["json"] = err
|
||||||
@ -134,37 +117,55 @@ func (o *OAuthController) Introspect() {
|
|||||||
o.ServeJSON()
|
o.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var whitelist = []string{
|
||||||
|
"/login",
|
||||||
|
"/refresh",
|
||||||
|
"/introspect",
|
||||||
|
}
|
||||||
|
|
||||||
// @Title AuthForward
|
// @Title AuthForward
|
||||||
// @Description auth forward
|
// @Description auth forward
|
||||||
// @Param Authorization header string false "auth token"
|
// @Param Authorization header string false "auth token"
|
||||||
// @Param body body models.workflow true "The workflow content"
|
|
||||||
// @Success 200 {string}
|
// @Success 200 {string}
|
||||||
// @router /forward [get]
|
// @router /forward [get]
|
||||||
func (o *OAuthController) InternalAuthForward() {
|
func (o *OAuthController) InternalAuthForward() {
|
||||||
|
fmt.Println("InternalAuthForward")
|
||||||
reqToken := o.Ctx.Request.Header.Get("Authorization")
|
reqToken := o.Ctx.Request.Header.Get("Authorization")
|
||||||
|
if reqToken == "" {
|
||||||
|
for _, w := range whitelist {
|
||||||
|
if strings.Contains(o.Ctx.Request.Header.Get("X-Forwarded-Uri"), w) {
|
||||||
|
o.Ctx.ResponseWriter.WriteHeader(200)
|
||||||
|
o.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o.Ctx.ResponseWriter.WriteHeader(401)
|
||||||
|
o.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
splitToken := strings.Split(reqToken, "Bearer ")
|
splitToken := strings.Split(reqToken, "Bearer ")
|
||||||
if len(splitToken) < 2 {
|
if len(splitToken) < 2 {
|
||||||
reqToken = ""
|
reqToken = ""
|
||||||
} else {
|
} else {
|
||||||
reqToken = splitToken[1]
|
reqToken = splitToken[1]
|
||||||
}
|
}
|
||||||
origin, publicKey, external := o.extractOrigin()
|
origin, publicKey, _ := o.extractOrigin()
|
||||||
if reqToken != "" && !o.checkAuthForward(reqToken, publicKey) && origin != "" {
|
if !infrastructure.GetAuthConnector().CheckAuthForward( //reqToken != "" &&
|
||||||
fmt.Println("Unauthorized", origin, reqToken)
|
reqToken, publicKey, origin,
|
||||||
|
o.Ctx.Request.Header.Get("X-Forwarded-Method"),
|
||||||
|
o.Ctx.Request.Header.Get("X-Forwarded-Uri")) && origin != "" && publicKey != "" {
|
||||||
o.Ctx.ResponseWriter.WriteHeader(401)
|
o.Ctx.ResponseWriter.WriteHeader(401)
|
||||||
o.ServeJSON()
|
o.ServeJSON()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
token, err := infrastructure.GetAuthConnector().Introspect(reqToken, &http.Cookie{
|
isToken, err := infrastructure.GetAuthConnector().Introspect(reqToken, &http.Cookie{
|
||||||
Name: "csrf_token",
|
Name: "csrf_token",
|
||||||
Value: o.XSRFToken(),
|
Value: o.XSRFToken(),
|
||||||
}) // may be a problem... we should check if token is valid on our side
|
}) // may be a problem... we should check if token is valid on our side
|
||||||
// prefers a refresh token call
|
// prefers a refresh token call
|
||||||
if err != nil || external {
|
fmt.Println("InternalAuthForward", isToken, err)
|
||||||
fmt.Println("Unauthorized 2", err, external) // error
|
if err != nil || !isToken {
|
||||||
o.Ctx.ResponseWriter.WriteHeader(401)
|
o.Ctx.ResponseWriter.WriteHeader(401)
|
||||||
} else if token && !external { // redirect to login
|
|
||||||
o.Data["json"] = token
|
|
||||||
}
|
}
|
||||||
o.ServeJSON()
|
o.ServeJSON()
|
||||||
}
|
}
|
||||||
@ -176,50 +177,25 @@ func (o *OAuthController) extractOrigin() (string, string, bool) {
|
|||||||
if origin == "" {
|
if origin == "" {
|
||||||
origin = o.Ctx.Request.Header.Get("Origin")
|
origin = o.Ctx.Request.Header.Get("Origin")
|
||||||
}
|
}
|
||||||
idLoc, loc := static.GetMyLocalJsonPeer()
|
searchStr := origin
|
||||||
|
r := regexp.MustCompile("(:[0-9]+)")
|
||||||
|
t := r.FindString(searchStr)
|
||||||
|
if t != "" {
|
||||||
|
searchStr = strings.Replace(searchStr, t, "", -1)
|
||||||
|
}
|
||||||
|
peer := oclib.Search(nil, searchStr, oclib.LibDataEnum(oclib.PEER))
|
||||||
|
if peer.Code != 200 || len(peer.Data) == 0 { // TODO: add state of partnership
|
||||||
|
return "", "", external
|
||||||
|
}
|
||||||
|
p := peer.Data[0].(*model.Peer)
|
||||||
|
publicKey = p.PublicKey
|
||||||
|
origin = p.Url
|
||||||
if origin != "" { // is external
|
if origin != "" { // is external
|
||||||
peer := oclib.Search(nil, origin, oclib.LibDataEnum(oclib.PEER))
|
if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") || p.State == model.SELF {
|
||||||
if peer.Code != 200 {
|
|
||||||
return "", "", external
|
|
||||||
}
|
|
||||||
p := peer.Data[0]
|
|
||||||
if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") || idLoc == p.GetID() {
|
|
||||||
external = false
|
external = false
|
||||||
}
|
}
|
||||||
publicKey = p.(*model.Peer).PublicKey
|
|
||||||
} else {
|
} else {
|
||||||
external = false
|
external = false
|
||||||
publicKey = loc["public_key"].(string)
|
|
||||||
}
|
}
|
||||||
return origin, publicKey, external
|
return origin, publicKey, external
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OAuthController) checkAuthForward(reqToken string, publicKey string) bool {
|
|
||||||
bytes, err := base64.StdEncoding.DecodeString(reqToken) // Converting data
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to Decode secret", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
var decodedToken map[string]interface{}
|
|
||||||
err = json.Unmarshal(bytes, &decodedToken)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to parse secret", err)
|
|
||||||
return false
|
|
||||||
} else if decodedToken["session"] != nil {
|
|
||||||
host := o.Ctx.Request.Header.Get("X-Forwarded-Host")
|
|
||||||
method := o.Ctx.Request.Header.Get("X-Forwarded-Method")
|
|
||||||
forward := o.Ctx.Request.Header.Get("X-Forwarded-Uri")
|
|
||||||
if forward == "" || method == "" {
|
|
||||||
fmt.Println("Forwarded headers are missing")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// ask keto for permission is in claims
|
|
||||||
ok, err := infrastructure.GetClaims().DecodeClaimsInToken(
|
|
||||||
host, method, forward, decodedToken["session"].(map[string]interface{}), publicKey)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to decode claims", err)
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -1,13 +1,45 @@
|
|||||||
version: '3.4'
|
version: '3.4'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
traefik:
|
||||||
|
image: traefik:v2.10.4
|
||||||
|
container_name: traefik
|
||||||
|
networks:
|
||||||
|
- catalog
|
||||||
|
command:
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
- "--log.level=DEBUG"
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
whoami: # TEST PURPOSE
|
||||||
|
image: traefik/whoami
|
||||||
|
container_name: whoami
|
||||||
|
networks:
|
||||||
|
- catalog
|
||||||
|
ports:
|
||||||
|
- "5000:80"
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.obg.entrypoints=web"
|
||||||
|
- "traefik.http.routers.obg.rule=Host(`localhost`)"
|
||||||
|
- "traefik.http.routers.obg.tls=false"
|
||||||
|
- "traefik.http.services.obg.loadbalancer.server.port=80"
|
||||||
|
- "traefik.http.routers.obg.middlewares=oc-auth"
|
||||||
oc-auth:
|
oc-auth:
|
||||||
image: 'oc-auth:latest'
|
image: 'oc-auth:latest'
|
||||||
ports:
|
ports:
|
||||||
- 8094:8080
|
- 8094:8080
|
||||||
container_name: oc-auth
|
container_name: oc-auth
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.middlewares.auth.forwardauth.address=http://oc-auth:8080/oc/forward"
|
||||||
|
- "traefik.http.middlewares.auth.forwardauth.authResponseHeaders=X-Forwarded-User"
|
||||||
|
- "traefik.http.services.auth.loadbalancer.server.port=8080"
|
||||||
environment:
|
environment:
|
||||||
PVK_PATH: /etc/oc/pvk.pem
|
|
||||||
LDAP_ENDPOINTS: ldap:389
|
LDAP_ENDPOINTS: ldap:389
|
||||||
LDAP_BINDDN: cn=admin,dc=example,dc=com
|
LDAP_BINDDN: cn=admin,dc=example,dc=com
|
||||||
LDAP_BINDPW: password
|
LDAP_BINDPW: password
|
||||||
@ -15,6 +47,8 @@ services:
|
|||||||
LDAP_ROLE_BASEDN: "ou=AppRoles,dc=example,dc=com"
|
LDAP_ROLE_BASEDN: "ou=AppRoles,dc=example,dc=com"
|
||||||
networks:
|
networks:
|
||||||
- catalog
|
- catalog
|
||||||
|
volumes:
|
||||||
|
- ./pem:/etc/oc/pem
|
||||||
networks:
|
networks:
|
||||||
catalog:
|
catalog:
|
||||||
external: true
|
external: true
|
@ -3,5 +3,7 @@
|
|||||||
"MONGO_DATABASE":"DC_myDC",
|
"MONGO_DATABASE":"DC_myDC",
|
||||||
"NATS_URL": "nats://nats:4222",
|
"NATS_URL": "nats://nats:4222",
|
||||||
"PORT" : 8080,
|
"PORT" : 8080,
|
||||||
"AUTH_CONNECTOR_HOST": "hydra"
|
"AUTH_CONNECTOR_HOST": "hydra",
|
||||||
|
"PRIVATE_KEY_PATH": "/etc/oc/pem/private.pem",
|
||||||
|
"PUBLIC_KEY_PATH": "/etc/oc/pem/public.pem"
|
||||||
}
|
}
|
5
go.mod
5
go.mod
@ -3,11 +3,12 @@ module oc-auth
|
|||||||
go 1.22.0
|
go 1.22.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20241025125832-c34e5579fcfc
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241030105814-5f05b73366ab
|
||||||
github.com/beego/beego/v2 v2.3.1
|
github.com/beego/beego/v2 v2.3.1
|
||||||
github.com/nats-io/nats.go v1.37.0
|
github.com/nats-io/nats.go v1.37.0
|
||||||
github.com/ory/hydra-client-go v1.11.8
|
github.com/ory/hydra-client-go v1.11.8
|
||||||
github.com/smartystreets/goconvey v1.7.2
|
github.com/smartystreets/goconvey v1.7.2
|
||||||
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/oauth2 v0.23.0
|
golang.org/x/oauth2 v0.23.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -69,7 +70,6 @@ require (
|
|||||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.10.0 // indirect
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||||
@ -113,6 +113,7 @@ require (
|
|||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.60.1 // indirect
|
github.com/prometheus/common v0.60.1 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/purnaresa/bulwark v0.0.0-20201001150757-1cec324746b2
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/rs/zerolog v1.33.0 // indirect
|
github.com/rs/zerolog v1.33.0 // indirect
|
||||||
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 // indirect
|
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 // indirect
|
||||||
|
8
go.sum
8
go.sum
@ -67,6 +67,12 @@ cloud.o-forge.io/core/oc-lib v0.0.0-20241023092234-cc8fc2df2161 h1:T4Lkp3H/I/dZb
|
|||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20241023092234-cc8fc2df2161/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241023092234-cc8fc2df2161/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20241025125832-c34e5579fcfc h1:kDoodLH2HuIuZ0oppb3z+9YBYl7XwneXlqSGlYh/BnY=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241025125832-c34e5579fcfc h1:kDoodLH2HuIuZ0oppb3z+9YBYl7XwneXlqSGlYh/BnY=
|
||||||
cloud.o-forge.io/core/oc-lib v0.0.0-20241025125832-c34e5579fcfc/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241025125832-c34e5579fcfc/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241030091613-1a5521237800 h1:uZ4Qrxk/KEpOfDq8QHjZankW7aZGLlDYLoM3CZowlR8=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241030091613-1a5521237800/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241030101941-20ce1f5ef37b h1:jFjjZ5sfHM6G17/TphmEhkC0crg75+33tunEmQ3Z6KI=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241030101941-20ce1f5ef37b/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241030105814-5f05b73366ab h1:hYUf9xXpqhp9w0eBfOWVi7c17iWpN+FL2FbhsAkmQ2E=
|
||||||
|
cloud.o-forge.io/core/oc-lib v0.0.0-20241030105814-5f05b73366ab/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
@ -451,6 +457,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
|
|||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
github.com/purnaresa/bulwark v0.0.0-20201001150757-1cec324746b2 h1:5w7Y/+01L0ErOp3qFiiAEpVlvzYJK2mjbLFcbBkx2OI=
|
||||||
|
github.com/purnaresa/bulwark v0.0.0-20201001150757-1cec324746b2/go.mod h1:/fUyI4rS5nHkKtgxNRU/uuFyhx9woSy3wKQSCQjqWN4=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
12
index.html
Normal file
12
index.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Hostname: a3ff4096def1
|
||||||
|
IP: 127.0.0.1
|
||||||
|
IP: 172.18.0.16
|
||||||
|
RemoteAddr: 172.18.0.1:46314
|
||||||
|
GET / HTTP/1.1
|
||||||
|
Host: localhost:5000
|
||||||
|
User-Agent: Wget/1.20.3 (linux-gnu)
|
||||||
|
Accept: */*
|
||||||
|
Accept-Encoding: identity
|
||||||
|
Connection: Keep-Alive
|
||||||
|
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
|
||||||
|
|
@ -12,15 +12,17 @@ type AuthConnector interface {
|
|||||||
Logout(token string, cookies ...*http.Cookie) (*Token, error)
|
Logout(token string, cookies ...*http.Cookie) (*Token, error)
|
||||||
Introspect(token string, cookie ...*http.Cookie) (bool, error)
|
Introspect(token string, cookie ...*http.Cookie) (bool, error)
|
||||||
Refresh(token *Token) (*Token, error)
|
Refresh(token *Token) (*Token, error)
|
||||||
|
CheckAuthForward(reqToken string, publicKey string, host string, method string, forward string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Token struct {
|
type Token struct {
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
ExpiresIn int `json:"expires_in"`
|
ExpiresIn int `json:"expires_in"`
|
||||||
Challenge string `json:"challenge"`
|
TokenType string `json:"token_type"`
|
||||||
Username string `json:"username,omitempty"`
|
|
||||||
Password string `json:"password,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Redirect struct {
|
type Redirect struct {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package auth_connectors
|
package auth_connectors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -8,10 +9,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"oc-auth/conf"
|
"oc-auth/conf"
|
||||||
|
"oc-auth/infrastructure/claims"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
oclib "cloud.o-forge.io/core/oc-lib"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/peer"
|
||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
"cloud.o-forge.io/core/oc-lib/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -81,10 +84,18 @@ func (a HydraConnector) challenge(username string, url string, challenge string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a HydraConnector) Refresh(token *Token) (*Token, error) {
|
func (a HydraConnector) Refresh(token *Token) (*Token, error) {
|
||||||
|
access := strings.Split(token.AccessToken, ".")
|
||||||
|
if len(access) > 2 {
|
||||||
|
token.AccessToken = strings.Join(access[0:2], ".")
|
||||||
|
}
|
||||||
isValid, err := a.Introspect(token.AccessToken)
|
isValid, err := a.Introspect(token.AccessToken)
|
||||||
if err != nil || !isValid {
|
if err != nil || !isValid {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
_, err = a.Logout(token.AccessToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return a.Login(token.Username)
|
return a.Login(token.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,32 +118,6 @@ func (a HydraConnector) tryLog(username string, url string, subpath string, chal
|
|||||||
return a.challenge(username, resp.Request.URL.String(), challenge, cookies...)
|
return a.challenge(username, resp.Request.URL.String(), challenge, cookies...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a HydraConnector) extractTokenFromFragment(fragment string) *Token {
|
|
||||||
splittedFragment := strings.Split(fragment, "#")
|
|
||||||
f := splittedFragment[0]
|
|
||||||
if len(splittedFragment) > 1 {
|
|
||||||
f = splittedFragment[1]
|
|
||||||
}
|
|
||||||
token := &Token{}
|
|
||||||
frags := strings.Split(f, "&")
|
|
||||||
for _, f := range frags {
|
|
||||||
splittedFrag := strings.Split(f, "=")
|
|
||||||
if len(splittedFrag) > 1 {
|
|
||||||
if splittedFrag[0] == "access_token" {
|
|
||||||
token.AccessToken = strings.ReplaceAll(splittedFrag[1], "ory_at_", "")
|
|
||||||
}
|
|
||||||
if splittedFrag[0] == "expires_in" {
|
|
||||||
i, err := strconv.Atoi(splittedFrag[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
token.ExpiresIn = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a HydraConnector) getClient() string {
|
func (a HydraConnector) getClient() string {
|
||||||
resp, err := a.Caller.CallGet(a.getPath(true, false), "/clients")
|
resp, err := a.Caller.CallGet(a.getPath(true, false), "/clients")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -148,44 +133,63 @@ func (a HydraConnector) getClient() string {
|
|||||||
|
|
||||||
func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Token, err error) {
|
func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Token, err error) {
|
||||||
clientID := a.getClient()
|
clientID := a.getClient()
|
||||||
redirect, challenge, cookies, err := a.tryLog(username, a.getPath(false, true),
|
redirect, _, cookies, err := a.tryLog(username, a.getPath(false, true),
|
||||||
"/auth?client_id="+clientID+"&response_type="+strings.ReplaceAll(a.ResponseType, " ", "%20")+"&scope="+strings.ReplaceAll(a.Scopes, " ", "%20")+"&state="+a.State,
|
"/auth?client_id="+clientID+"&response_type="+strings.ReplaceAll(a.ResponseType, " ", "%20")+"&scope="+strings.ReplaceAll(a.Scopes, " ", "%20")+"&state="+a.State,
|
||||||
"login", cookies...)
|
"login", cookies...)
|
||||||
if err != nil || redirect == nil {
|
if err != nil || redirect == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
redirect, challenge, cookies, err = a.tryLog(username, a.urlFormat(redirect.RedirectTo, a.getPath(false, true)), "", "consent", cookies...)
|
redirect, _, cookies, err = a.tryLog(username, a.urlFormat(redirect.RedirectTo, a.getPath(false, true)), "", "consent", cookies...)
|
||||||
if err != nil || redirect == nil {
|
if err != nil || redirect == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// problem with consent THERE we need to accept the consent challenge && get the token
|
// problem with consent THERE we need to accept the consent challenge && get the token
|
||||||
url := ""
|
_, err = a.Caller.CallRaw(http.MethodGet, a.urlFormat(redirect.RedirectTo, a.getPath(false, true)), "", map[string]interface{}{},
|
||||||
resp, err := a.Caller.CallRaw(http.MethodGet, a.urlFormat(redirect.RedirectTo, a.getPath(false, true)), "", map[string]interface{}{},
|
|
||||||
"application/json", true, cookies...)
|
"application/json", true, cookies...)
|
||||||
|
fmt.Println(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s := strings.Split(err.Error(), "\"")
|
s := strings.Split(err.Error(), "\"")
|
||||||
if len(s) > 1 && strings.Contains(s[1], "access_token") {
|
if len(s) > 1 && strings.Contains(s[1], "access_token") {
|
||||||
url = s[1]
|
|
||||||
err = nil
|
err = nil
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
url = resp.Request.Response.Request.URL.Fragment
|
|
||||||
}
|
}
|
||||||
token := a.extractTokenFromFragment(url)
|
token := &Token{
|
||||||
fmt.Println(url, token)
|
Username: username,
|
||||||
if token == nil || token.AccessToken == "" {
|
|
||||||
return nil, errors.New("no token found")
|
|
||||||
}
|
}
|
||||||
token.Challenge = challenge
|
urls := url.Values{}
|
||||||
token.Active = true
|
urls.Add("client_id", clientID)
|
||||||
token.Username = username
|
urls.Add("client_secret", conf.GetConfig().ClientSecret)
|
||||||
fmt.Println(token)
|
urls.Add("grant_type", "client_credentials")
|
||||||
|
resp, err := a.Caller.CallForm(http.MethodPost, a.getPath(false, true), "/token", urls,
|
||||||
|
"application/x-www-form-urlencoded", true, cookies...)
|
||||||
|
var m map[string]interface{}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
b, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(b, &token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
json.Unmarshal(b, &m)
|
||||||
|
pp := oclib.Search(nil, string(peer.SELF.EnumIndex()), oclib.LibDataEnum(oclib.PEER))
|
||||||
|
if len(pp.Data) == 0 || pp.Code >= 300 || pp.Err != "" {
|
||||||
|
return nil, errors.New("peer not found")
|
||||||
|
}
|
||||||
|
c := claims.GetClaims().AddClaimsToToken(username, pp.Data[0].(*peer.Peer).Url)
|
||||||
|
b, _ = json.Marshal(c)
|
||||||
|
token.AccessToken = strings.ReplaceAll(token.AccessToken, "ory_at_", "") + "." + base64.StdEncoding.EncodeToString(b)
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a HydraConnector) Logout(token string, cookies ...*http.Cookie) (*Token, error) {
|
func (a HydraConnector) Logout(token string, cookies ...*http.Cookie) (*Token, error) {
|
||||||
|
access := strings.Split(token, ".")
|
||||||
|
if len(access) > 2 {
|
||||||
|
token = strings.Join(access[0:2], ".")
|
||||||
|
}
|
||||||
p := a.getPath(false, true) + "/revoke"
|
p := a.getPath(false, true) + "/revoke"
|
||||||
urls := url.Values{}
|
urls := url.Values{}
|
||||||
urls.Add("token", token)
|
urls.Add("token", token)
|
||||||
@ -203,6 +207,10 @@ func (a HydraConnector) Logout(token string, cookies ...*http.Cookie) (*Token, e
|
|||||||
func (a HydraConnector) Introspect(token string, cookie ...*http.Cookie) (bool, error) {
|
func (a HydraConnector) Introspect(token string, cookie ...*http.Cookie) (bool, error) {
|
||||||
// check validity of the token by calling introspect endpoint
|
// check validity of the token by calling introspect endpoint
|
||||||
// if token is not active, we need to re-authenticate by sending the user to the login page
|
// if token is not active, we need to re-authenticate by sending the user to the login page
|
||||||
|
access := strings.Split(token, ".")
|
||||||
|
if len(access) > 2 {
|
||||||
|
token = strings.Join(access[0:2], ".")
|
||||||
|
}
|
||||||
urls := url.Values{}
|
urls := url.Values{}
|
||||||
urls.Add("token", token)
|
urls.Add("token", token)
|
||||||
resp, err := a.Caller.CallForm(http.MethodPost, a.getPath(true, true), "/introspect", urls,
|
resp, err := a.Caller.CallForm(http.MethodPost, a.getPath(true, true), "/introspect", urls,
|
||||||
@ -238,3 +246,29 @@ func (a HydraConnector) getPath(isAdmin bool, isOauth bool) string {
|
|||||||
return "http://" + host + ":" + port + oauth
|
return "http://" + host + ":" + port + oauth
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a HydraConnector) CheckAuthForward(reqToken string, publicKey string, host string, method string, forward string) bool {
|
||||||
|
fmt.Println("CheckAuthForward", reqToken, publicKey, host, method, forward)
|
||||||
|
if forward == "" || method == "" {
|
||||||
|
fmt.Println("Forwarded headers are missing")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var c claims.Claims
|
||||||
|
token := strings.Split(reqToken, ".")
|
||||||
|
if len(token) > 2 {
|
||||||
|
bytes, err := base64.StdEncoding.DecodeString(token[2])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(bytes, &c)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ask keto for permission is in claims
|
||||||
|
ok, err := claims.GetClaims().DecodeClaimsInToken(host, method, forward, c, publicKey)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to decode claims", err)
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package claims
|
package claims
|
||||||
|
|
||||||
|
import "oc-auth/conf"
|
||||||
|
|
||||||
// Tokenizer interface
|
// Tokenizer interface
|
||||||
type ClaimService interface {
|
type ClaimService interface {
|
||||||
AddClaimsToToken(userId string, host string) Claims
|
AddClaimsToToken(userId string, host string) Claims
|
||||||
DecodeClaimsInToken(host string, method string, forward string, sessionClaims map[string]interface{}, publicKey string) (bool, error)
|
DecodeClaimsInToken(host string, method string, forward string, sessionClaims Claims, publicKey string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionClaims struct
|
// SessionClaims struct
|
||||||
@ -16,3 +18,11 @@ type SessionClaims struct {
|
|||||||
type Claims struct {
|
type Claims struct {
|
||||||
Session SessionClaims `json:"session"`
|
Session SessionClaims `json:"session"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var t = map[string]ClaimService{
|
||||||
|
"hydra": HydraClaims{},
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetClaims() ClaimService {
|
||||||
|
return t[conf.GetConfig().Auth]
|
||||||
|
}
|
||||||
|
129
infrastructure/claims/crypto.go
Normal file
129
infrastructure/claims/crypto.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package claims
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SignDefault(plaintext, privateKey []byte) (signature string, err error) {
|
||||||
|
client, err := New(privateKey, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
signatureByte, err := client.Sign(plaintext)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
signature = base64.StdEncoding.EncodeToString(signatureByte)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyDefault(plaintext, publicKey []byte, signature string) (err error) {
|
||||||
|
publicKeys := make(map[string][]byte)
|
||||||
|
publicKeys["default"] = publicKey
|
||||||
|
client, err := New(nil, publicKeys)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureByte, err := base64.StdEncoding.DecodeString(signature)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.Verify(plaintext, signatureByte, "default")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Sign(plaintext []byte) (signature []byte, err error) {
|
||||||
|
var opts rsa.PSSOptions
|
||||||
|
opts.SaltLength = rsa.PSSSaltLengthAuto
|
||||||
|
|
||||||
|
newhash := crypto.SHA256
|
||||||
|
pssh := newhash.New()
|
||||||
|
pssh.Write(plaintext)
|
||||||
|
hashed := pssh.Sum(nil)
|
||||||
|
signature, err = rsa.SignPSS(
|
||||||
|
rand.Reader,
|
||||||
|
c.PrivateKey,
|
||||||
|
newhash,
|
||||||
|
hashed,
|
||||||
|
&opts,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Verify(plaintext, signature []byte, target string) (err error) {
|
||||||
|
var opts rsa.PSSOptions
|
||||||
|
opts.SaltLength = rsa.PSSSaltLengthAuto
|
||||||
|
|
||||||
|
newhash := crypto.SHA256
|
||||||
|
pssh := newhash.New()
|
||||||
|
pssh.Write(plaintext)
|
||||||
|
hashed := pssh.Sum(nil)
|
||||||
|
err = rsa.VerifyPSS(
|
||||||
|
c.PublicKeys[target],
|
||||||
|
newhash,
|
||||||
|
hashed,
|
||||||
|
signature,
|
||||||
|
&opts,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
PrivateKey *rsa.PrivateKey
|
||||||
|
PublicKeys map[string]*rsa.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(privateKey []byte, publicKeys map[string][]byte) (client *Client, err error) {
|
||||||
|
client = &Client{}
|
||||||
|
|
||||||
|
if privateKey != nil {
|
||||||
|
validPrivateKey, errPrivate := x509.ParsePKCS1PrivateKey(privateKey)
|
||||||
|
if errPrivate != nil {
|
||||||
|
err = errPrivate
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client.PrivateKey = validPrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
if publicKeys != nil {
|
||||||
|
validPublicKeysMap := make(map[string]*rsa.PublicKey)
|
||||||
|
for k, v := range publicKeys {
|
||||||
|
validPublicKey, errPublic := x509.ParsePKCS1PublicKey(v)
|
||||||
|
if errPublic != nil {
|
||||||
|
err = errPublic
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if validPublicKey == nil {
|
||||||
|
err = errors.New("Invalid Public Key Type")
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
validPublicKeysMap[k] = validPublicKey
|
||||||
|
}
|
||||||
|
client.PublicKeys = validPublicKeysMap
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -1,13 +1,10 @@
|
|||||||
package claims
|
package claims
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"oc-auth/conf"
|
"oc-auth/conf"
|
||||||
"oc-auth/infrastructure/perms_connectors"
|
"oc-auth/infrastructure/perms_connectors"
|
||||||
"oc-auth/infrastructure/utils"
|
"oc-auth/infrastructure/utils"
|
||||||
@ -43,11 +40,10 @@ func (h HydraClaims) decodeKey(key string) (tools.METHOD, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h HydraClaims) DecodeSignature(host string, signature string, publicKey string) (bool, error) {
|
func (h HydraClaims) DecodeSignature(host string, signature string, publicKey string) (bool, error) {
|
||||||
|
fmt.Println("DecodeSignature", host)
|
||||||
hashed := sha256.Sum256([]byte(host))
|
hashed := sha256.Sum256([]byte(host))
|
||||||
// get public key into a variable
|
spkiBlock, _ := pem.Decode([]byte(publicKey)) // get public key into a variable
|
||||||
spkiBlock, _ := pem.Decode([]byte(publicKey))
|
err := VerifyDefault(hashed[:], spkiBlock.Bytes, signature)
|
||||||
key, _ := x509.ParsePKCS1PublicKey(spkiBlock.Bytes)
|
|
||||||
err := rsa.VerifyPKCS1v15(key, crypto.SHA256, hashed[:], []byte(signature))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -55,32 +51,28 @@ func (h HydraClaims) DecodeSignature(host string, signature string, publicKey st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h HydraClaims) encodeSignature(host string) (string, error) {
|
func (h HydraClaims) encodeSignature(host string) (string, error) {
|
||||||
|
fmt.Println("encodeSignature", host)
|
||||||
hashed := sha256.Sum256([]byte(host))
|
hashed := sha256.Sum256([]byte(host))
|
||||||
// READ FILE TO GET PRIVATE KEY FROM PVK PEM PATH
|
// READ FILE TO GET PRIVATE KEY FROM PVK PEM PATH
|
||||||
content, err := os.ReadFile(conf.GetConfig().PVKPath)
|
content, err := os.ReadFile(conf.GetConfig().PrivateKeyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
privateKey := string(content)
|
privateKey := string(content)
|
||||||
spkiBlock, _ := pem.Decode([]byte(privateKey))
|
spkiBlock, _ := pem.Decode([]byte(privateKey))
|
||||||
key, _ := x509.ParsePKCS1PrivateKey(spkiBlock.Bytes)
|
return SignDefault(hashed[:], spkiBlock.Bytes)
|
||||||
signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hashed[:])
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(signature), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h HydraClaims) DecodeClaimsInToken(host string, method string, forward string, sessionClaims map[string]interface{}, publicKey string) (bool, error) {
|
func (h HydraClaims) DecodeClaimsInToken(host string, method string, forward string, sessionClaims Claims, publicKey string) (bool, error) {
|
||||||
if sessionClaims["id_token"] == nil || sessionClaims["access_token"] == nil {
|
idTokenClaims := sessionClaims.Session.IDToken
|
||||||
return false, errors.New("invalid session claims")
|
if idTokenClaims["signature"] == nil {
|
||||||
|
return false, errors.New("no signature found")
|
||||||
}
|
}
|
||||||
idTokenClaims := sessionClaims["id_token"].(map[string]interface{})
|
|
||||||
signature := idTokenClaims["signature"].(string)
|
signature := idTokenClaims["signature"].(string)
|
||||||
if ok, err := h.DecodeSignature(host, signature, publicKey); !ok {
|
if ok, err := h.DecodeSignature(host, signature, publicKey); !ok {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
claims := sessionClaims["access_token"].(map[string]interface{})
|
claims := sessionClaims.Session.AccessToken
|
||||||
path := strings.ReplaceAll(forward, "http://"+host, "")
|
path := strings.ReplaceAll(forward, "http://"+host, "")
|
||||||
splittedPath := strings.Split(path, "/")
|
splittedPath := strings.Split(path, "/")
|
||||||
for m, p := range claims {
|
for m, p := range claims {
|
||||||
@ -114,6 +106,8 @@ func (h HydraClaims) AddClaimsToToken(userId string, host string) Claims {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return claims
|
return claims
|
||||||
}
|
}
|
||||||
|
claims.Session.AccessToken = make(map[string]interface{})
|
||||||
|
claims.Session.IDToken = make(map[string]interface{})
|
||||||
for _, perm := range perms {
|
for _, perm := range perms {
|
||||||
key, err := h.generateKey(perm.Relation, perm.Object)
|
key, err := h.generateKey(perm.Relation, perm.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -127,7 +121,6 @@ func (h HydraClaims) AddClaimsToToken(userId string, host string) Claims {
|
|||||||
}
|
}
|
||||||
claims.Session.IDToken["signature"] = sign
|
claims.Session.IDToken["signature"] = sign
|
||||||
return claims
|
return claims
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add signature in the token MISSING
|
// add signature in the token MISSING
|
||||||
|
@ -9,10 +9,6 @@ import (
|
|||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
"cloud.o-forge.io/core/oc-lib/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
var t = map[string]claims.ClaimService{
|
|
||||||
"hydra": claims.HydraClaims{},
|
|
||||||
}
|
|
||||||
|
|
||||||
var a = map[string]auth_connectors.AuthConnector{
|
var a = map[string]auth_connectors.AuthConnector{
|
||||||
"hydra": auth_connectors.HydraConnector{
|
"hydra": auth_connectors.HydraConnector{
|
||||||
Caller: tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{}),
|
Caller: tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{}),
|
||||||
@ -28,5 +24,5 @@ func GetPermissionConnector() perms_connectors.PermConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetClaims() claims.ClaimService {
|
func GetClaims() claims.ClaimService {
|
||||||
return t[conf.GetConfig().Auth]
|
return claims.GetClaims()
|
||||||
}
|
}
|
||||||
|
@ -1,466 +0,0 @@
|
|||||||
# Ory Hydra Configuration
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# !!WARNING!!
|
|
||||||
# This configuration file is for documentation purposes only. Do not use it in production. As all configuration items
|
|
||||||
# are enabled, it will not work out of the box either.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Ory Hydra can be configured using a configuration file and passing the file location using `--config path/to/config.yaml`.
|
|
||||||
# Per default, Ory Hydra will look up and load file ~/.hydra.yaml. All configuration keys can be set using environment
|
|
||||||
# variables as well.
|
|
||||||
#
|
|
||||||
# Setting environment variables is easy:
|
|
||||||
#
|
|
||||||
## Linux / OSX
|
|
||||||
#
|
|
||||||
# $ export MY_ENV_VAR=foo
|
|
||||||
# $ hydra ...
|
|
||||||
#
|
|
||||||
# alternatively:
|
|
||||||
#
|
|
||||||
# $ MY_ENV_VAR=foo hydra ...
|
|
||||||
#
|
|
||||||
## Windows
|
|
||||||
#
|
|
||||||
### Command Prompt
|
|
||||||
#
|
|
||||||
# > set MY_ENV_VAR=foo
|
|
||||||
# > hydra ...
|
|
||||||
#
|
|
||||||
### Powershell
|
|
||||||
#
|
|
||||||
# > $env:MY_ENV_VAR="foo"
|
|
||||||
# > hydra ...
|
|
||||||
#
|
|
||||||
## Docker
|
|
||||||
#
|
|
||||||
# $ docker run -e MY_ENV_VAR=foo oryd/hydra:...
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Assuming the following configuration layout:
|
|
||||||
#
|
|
||||||
# serve:
|
|
||||||
# public:
|
|
||||||
# port: 4444
|
|
||||||
# something_else: foobar
|
|
||||||
#
|
|
||||||
# Key `something_else` can be set as an environment variable by uppercasing it's path:
|
|
||||||
# `serve.public.port.somethihng_else` -> `SERVE.PUBLIC.PORT.SOMETHING_ELSE`
|
|
||||||
# and replacing `.` with `_`:
|
|
||||||
# `serve.public.port.somethihng_else` -> `SERVE_PUBLIC_PORT_SOMETHING_ELSE`
|
|
||||||
#
|
|
||||||
# Environment variables always override values from the configuration file. Here are some more examples:
|
|
||||||
#
|
|
||||||
# Configuration key | Environment variable |
|
|
||||||
# ------------------|----------------------|
|
|
||||||
# dsn | DSN |
|
|
||||||
# serve.admin.host | SERVE_ADMIN_HOST |
|
|
||||||
# ------------------|----------------------|
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# List items such as
|
|
||||||
#
|
|
||||||
#secrets:
|
|
||||||
# system:
|
|
||||||
# - oc-auth-got-secret
|
|
||||||
# - this-is-an-old-secret
|
|
||||||
# - this-is-another-old-secret
|
|
||||||
#
|
|
||||||
# must be separated using `,` when using environment variables. The environment variable equivalent to the code section#
|
|
||||||
# above is:
|
|
||||||
#
|
|
||||||
# Linux/macOS: $ export SECRETS_SYSTEM=this-is-the-primary-secret,this-is-an-old-secret,this-is-another-old-secret
|
|
||||||
# Windows: > set SECRETS_SYSTEM=this-is-the-primary-secret,this-is-an-old-secret,this-is-another-old-secret
|
|
||||||
|
|
||||||
# log configures the logger
|
|
||||||
log:
|
|
||||||
# Sets the log level, supports "panic", "fatal", "error", "warn", "info" and "debug". Defaults to "info".
|
|
||||||
level: info
|
|
||||||
# Sets the log format. Leave it undefined for text based log format, or set to "json" for JSON formatting.
|
|
||||||
format: json
|
|
||||||
|
|
||||||
# serve controls the configuration for the http(s) daemon(s).
|
|
||||||
serve:
|
|
||||||
# public controls the public daemon serving public API endpoints like /oauth2/auth, /oauth2/token, /.well-known/jwks.json
|
|
||||||
public:
|
|
||||||
# The port to listen on. Defaults to 4444
|
|
||||||
port: 4444
|
|
||||||
# The interface or unix socket Ory Hydra should listen and handle public API requests on.
|
|
||||||
# Use the prefix "unix:" to specify a path to a unix socket.
|
|
||||||
# Leave empty to listen on all interfaces.
|
|
||||||
host: localhost # leave this out or empty to listen on all devices which is the default
|
|
||||||
# host: unix:/path/to/socket
|
|
||||||
# socket:
|
|
||||||
# owner: hydra
|
|
||||||
# group: hydra
|
|
||||||
# mode: 0775
|
|
||||||
|
|
||||||
# cors configures Cross Origin Resource Sharing for public endpoints.
|
|
||||||
cors:
|
|
||||||
# set enabled to true to enable CORS. Defaults to false.
|
|
||||||
enabled: true
|
|
||||||
# allowed_origins is a list of origins (comma separated values) a cross-domain request can be executed from.
|
|
||||||
# If the special * value is present in the list, all origins will be allowed. An origin may contain a wildcard (*)
|
|
||||||
# to replace 0 or more characters (i.e.: http://*.domain.com). Only one wildcard can be used per origin.
|
|
||||||
#
|
|
||||||
# If empty or undefined, this defaults to `*`, allowing CORS from every domain (if cors.enabled: true).
|
|
||||||
allowed_origins:
|
|
||||||
- https://example.com
|
|
||||||
- https://*.example.com
|
|
||||||
# allowed_methods is list of HTTP methods the user agent is allowed to use with cross-domain
|
|
||||||
# requests. Defaults to the methods listed.
|
|
||||||
allowed_methods:
|
|
||||||
- POST
|
|
||||||
- GET
|
|
||||||
- PUT
|
|
||||||
- PATCH
|
|
||||||
- DELETE
|
|
||||||
|
|
||||||
# A list of non simple headers the client is allowed to use with cross-domain requests. Defaults to the listed values.
|
|
||||||
allowed_headers:
|
|
||||||
- Authorization
|
|
||||||
- Content-Type
|
|
||||||
|
|
||||||
# Sets which headers (comma separated values) are safe to expose to the API of a CORS API specification. Defaults to the listed values.
|
|
||||||
exposed_headers:
|
|
||||||
- Content-Type
|
|
||||||
|
|
||||||
# Sets whether the request can include user credentials like cookies, HTTP authentication
|
|
||||||
# or client side SSL certificates. Defaults to true.
|
|
||||||
allow_credentials: true
|
|
||||||
|
|
||||||
# Sets how long (in seconds) the results of a preflight request can be cached. If set to 0, every request
|
|
||||||
# is preceded by a preflight request. Defaults to 0.
|
|
||||||
max_age: 10
|
|
||||||
|
|
||||||
# If set to true, adds additional log output to debug server side CORS issues. Defaults to false.
|
|
||||||
debug: true
|
|
||||||
|
|
||||||
# Access Log configuration for public server.
|
|
||||||
request_log:
|
|
||||||
# Disable access log for health and metrics endpoints.
|
|
||||||
disable_for_health: false
|
|
||||||
|
|
||||||
# admin controls the admin daemon serving admin API endpoints like /jwk, /client, ...
|
|
||||||
admin:
|
|
||||||
# The port to listen on. Defaults to 4445
|
|
||||||
port: 4445
|
|
||||||
# The interface or unix socket Ory Hydra should listen and handle administrative API requests on.
|
|
||||||
# Use the prefix "unix:" to specify a path to a unix socket.
|
|
||||||
# Leave empty to listen on all interfaces.
|
|
||||||
host: localhost # leave this out or empty to listen on all devices which is the default
|
|
||||||
# host: unix:/path/to/socket
|
|
||||||
# socket:
|
|
||||||
# owner: hydra
|
|
||||||
# group: hydra
|
|
||||||
# mode: 0775
|
|
||||||
|
|
||||||
# cors configures Cross Origin Resource Sharing for admin endpoints.
|
|
||||||
cors:
|
|
||||||
# set enabled to true to enable CORS. Defaults to false.
|
|
||||||
enabled: true
|
|
||||||
# allowed_origins is a list of origins (comma separated values) a cross-domain request can be executed from.
|
|
||||||
# If the special * value is present in the list, all origins will be allowed. An origin may contain a wildcard (*)
|
|
||||||
# to replace 0 or more characters (i.e.: http://*.domain.com). Only one wildcard can be used per origin.
|
|
||||||
#
|
|
||||||
# If empty or undefined, this defaults to `*`, allowing CORS from every domain (if cors.enabled: true).
|
|
||||||
allowed_origins:
|
|
||||||
- https://example.com
|
|
||||||
- https://*.example.com
|
|
||||||
# allowed_methods is list of HTTP methods the user agent is allowed to use with cross-domain
|
|
||||||
# requests. Defaults to GET and POST.
|
|
||||||
allowed_methods:
|
|
||||||
- POST
|
|
||||||
- GET
|
|
||||||
- PUT
|
|
||||||
- PATCH
|
|
||||||
- DELETE
|
|
||||||
|
|
||||||
# A list of non simple headers the client is allowed to use with cross-domain requests. Defaults to the listed values.
|
|
||||||
allowed_headers:
|
|
||||||
- Authorization
|
|
||||||
- Content-Type
|
|
||||||
|
|
||||||
# Sets which headers (comma separated values) are safe to expose to the API of a CORS API specification. Defaults to the listed values.
|
|
||||||
exposed_headers:
|
|
||||||
- Content-Type
|
|
||||||
|
|
||||||
# Sets whether the request can include user credentials like cookies, HTTP authentication
|
|
||||||
# or client side SSL certificates.
|
|
||||||
allow_credentials: true
|
|
||||||
|
|
||||||
# Sets how long (in seconds) the results of a preflight request can be cached. If set to 0, every request
|
|
||||||
# is preceded by a preflight request. Defaults to 0.
|
|
||||||
max_age: 10
|
|
||||||
|
|
||||||
# If set to true, adds additional log output to debug server side CORS issues. Defaults to false.
|
|
||||||
debug: true
|
|
||||||
|
|
||||||
# Access Log configuration for admin server.
|
|
||||||
request_log:
|
|
||||||
# Disable access log for health endpoints.
|
|
||||||
disable_for_health: false
|
|
||||||
|
|
||||||
# tls configures HTTPS (HTTP over TLS). If configured, the server automatically supports HTTP/2.
|
|
||||||
tls:
|
|
||||||
# key configures the private key (pem encoded)
|
|
||||||
key:
|
|
||||||
# The key can either be loaded from a file:
|
|
||||||
path: /path/to/key.pem
|
|
||||||
# Or from a base64 encoded (without padding) string:
|
|
||||||
base64: LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLVxuTUlJRkRqQkFCZ2txaGtpRzl3MEJCUTB3...
|
|
||||||
|
|
||||||
# cert configures the TLS certificate (PEM encoded)
|
|
||||||
cert:
|
|
||||||
# The cert can either be loaded from a file:
|
|
||||||
path: /path/to/cert.pem
|
|
||||||
# Or from a base64 encoded (without padding) string:
|
|
||||||
base64: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXG5NSUlEWlRDQ0FrMmdBd0lCQWdJRVY1eE90REFOQmdr...
|
|
||||||
|
|
||||||
# Whitelist one or multiple CIDR address ranges and allow them to terminate TLS connections.
|
|
||||||
# Be aware that the X-Forwarded-Proto header must be set and must never be modifiable by anyone but
|
|
||||||
# your proxy / gateway / load balancer. Supports ipv4 and ipv6.
|
|
||||||
#
|
|
||||||
# Hydra serves http instead of https when this option is set.
|
|
||||||
#
|
|
||||||
# For more information head over to: https://www.ory.sh/docs/hydra/production#tls-termination
|
|
||||||
allow_termination_from:
|
|
||||||
- 127.0.0.1/32
|
|
||||||
cookies:
|
|
||||||
# specify the SameSite mode that cookies should be sent with
|
|
||||||
same_site_mode: Lax
|
|
||||||
|
|
||||||
# Some older browser versions don't work with SameSite=None. This option enables the workaround
|
|
||||||
# defined in https://web.dev/samesite-cookie-recipes/ which essentially stores a second cookie
|
|
||||||
# without SameSite as a fallback.
|
|
||||||
same_site_legacy_workaround: false
|
|
||||||
|
|
||||||
# dsn sets the data source name. This configures the backend where Ory Hydra persists data.
|
|
||||||
#
|
|
||||||
## In-memory database
|
|
||||||
#
|
|
||||||
# If dsn is "memory", data will be written to memory and is lost when you restart this instance.
|
|
||||||
# You can set this value using the DSN environment variable:
|
|
||||||
#
|
|
||||||
## SQL databases
|
|
||||||
#
|
|
||||||
# Ory Hydra supports popular SQL databases. For more detailed configuration information go to:
|
|
||||||
# https://www.ory.sh/docs/hydra/dependencies-environment#sql
|
|
||||||
#
|
|
||||||
### PostgreSQL (recommended)
|
|
||||||
#
|
|
||||||
# If dsn is starting with postgres:// PostgreSQL will be used as storage backend:
|
|
||||||
# dsn: dsn=postgres://user:password@host:123/database
|
|
||||||
#
|
|
||||||
### MySQL database
|
|
||||||
#
|
|
||||||
# If dsn is starting with mysql:// MySQL will be used as storage backend:
|
|
||||||
# dsn: mysql://user:password@tcp(host:123)/database
|
|
||||||
#
|
|
||||||
### CockroachDB
|
|
||||||
#
|
|
||||||
# If dsn is starting with cockroach:// CockroachDB will be used as storage backend:
|
|
||||||
# dsn: cockroach://user:password@host:123/database
|
|
||||||
#
|
|
||||||
dsn: memory
|
|
||||||
# dsn: postgres://user:password@host:123/database
|
|
||||||
# dsn: mysql://user:password@tcp(host:123)/database
|
|
||||||
|
|
||||||
# hsm configures Hardware Security Module for hydra.openid.id-token, hydra.jwt.access-token keys
|
|
||||||
# Either slot or token_label must be set. If token_label is set, then first slot in index with this label is used.
|
|
||||||
hsm:
|
|
||||||
enabled: false
|
|
||||||
library: /path/to/hsm-vendor/library.so
|
|
||||||
pin: token-pin-code
|
|
||||||
slot: 0
|
|
||||||
token_label: hydra
|
|
||||||
# Key set prefix can be used in case of multiple Ory Hydra instances need to store keys on the same HSM partition.
|
|
||||||
# For example if `hsm.key_set_prefix=app1.` then key set `hydra.openid.id-token` would be generated/requested/deleted
|
|
||||||
# on HSM with `CKA_LABEL=app1.hydra.openid.id-token`.
|
|
||||||
key_set_prefix: app1.
|
|
||||||
|
|
||||||
# webfinger configures ./well-known/ settings
|
|
||||||
webfinger:
|
|
||||||
# jwks configures the /.well-known/jwks.json endpoint.
|
|
||||||
jwks:
|
|
||||||
# broadcast_keys is a list of JSON Web Keys that should be exposed at that endpoint. This is usually
|
|
||||||
# the public key for verifying OpenID Connect ID Tokens. However, you might want to add additional keys here as well.
|
|
||||||
broadcast_keys:
|
|
||||||
- hydra.openid.id-token # This key is always exposed by default
|
|
||||||
# - hydra.jwt.access-token # This key will be exposed when the OAuth2 Access Token strategy is set to JWT.
|
|
||||||
|
|
||||||
# oidc_discovery configures OpenID Connect Discovery (/.well-known/openid-configuration)
|
|
||||||
oidc_discovery:
|
|
||||||
client_registration_url: https://my-service.com/clients
|
|
||||||
# A list of supported claims to be broadcasted. Claim `sub` is always included:
|
|
||||||
supported_claims:
|
|
||||||
- email
|
|
||||||
- username
|
|
||||||
# The scope OAuth 2.0 Clients may request. Scope `offline`, `offline_access`, and `openid` are always included.
|
|
||||||
supported_scope:
|
|
||||||
- email
|
|
||||||
- whatever
|
|
||||||
- read.photos
|
|
||||||
|
|
||||||
# A URL of the userinfo endpoint to be advertised at the OpenID Connect
|
|
||||||
# Discovery endpoint /.well-known/openid-configuration. Defaults to Ory Hydra's userinfo endpoint at /userinfo.
|
|
||||||
# Set this value if you want to handle this endpoint yourself.
|
|
||||||
userinfo_url: https://example.org/my-custom-userinfo-endpoint
|
|
||||||
|
|
||||||
# oidc configures OpenID Connect features.
|
|
||||||
oidc:
|
|
||||||
# subject_identifiers configures the Subject Identifier algorithm.
|
|
||||||
#
|
|
||||||
# For more information please head over to the documentation:
|
|
||||||
# -> https://www.ory.sh/docs/hydra/advanced#subject-identifier-algorithms
|
|
||||||
subject_identifiers:
|
|
||||||
# which algorithms to enable. Defaults to "public"
|
|
||||||
supported_types:
|
|
||||||
- pairwise
|
|
||||||
- public
|
|
||||||
# configures the pairwise algorithm
|
|
||||||
pairwise:
|
|
||||||
# if "pairwise" is enabled, the salt must be defined.
|
|
||||||
salt: some-random-salt
|
|
||||||
|
|
||||||
# dynamic_client_registration configures OpenID Connect Dynamic Client Registration (exposed as admin endpoints /clients/...)
|
|
||||||
dynamic_client_registration:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# The OpenID Connect Dynamic Client Registration specification has no concept of whitelisting OAuth 2.0 Scope. If you
|
|
||||||
# want to expose Dynamic Client Registration, you should set the default scope enabled for newly registered clients.
|
|
||||||
# Keep in mind that users can overwrite this default by setting the "scope" key in the registration payload,
|
|
||||||
# effectively disabling the concept of whitelisted scopes.
|
|
||||||
default_scope:
|
|
||||||
- openid
|
|
||||||
- offline
|
|
||||||
- offline_access
|
|
||||||
|
|
||||||
urls:
|
|
||||||
self:
|
|
||||||
# This value will be used as the "issuer" in access and ID tokens. It must be
|
|
||||||
# specified and using HTTPS protocol, unless --dev is set. This should typically be equal
|
|
||||||
# to the public value.
|
|
||||||
issuer: https://localhost:4444/
|
|
||||||
|
|
||||||
# This is the base location of the public endpoints of your Ory Hydra installation. This should typically be equal
|
|
||||||
# to the issuer value. If left unspecified, it falls back to the issuer value.
|
|
||||||
public: https://localhost:4444/
|
|
||||||
|
|
||||||
# Sets the login endpoint of the User Login & Consent flow. Defaults to an internal fallback URL.
|
|
||||||
login: https://my-login.app/login
|
|
||||||
# Sets the consent endpoint of the User Login & Consent flow. Defaults to an internal fallback URL.
|
|
||||||
consent: https://my-consent.app/consent
|
|
||||||
# Sets the logout endpoint. Defaults to an internal fallback URL.
|
|
||||||
logout: https://my-logout.app/logout
|
|
||||||
# Sets the error endpoint. The error ui will be shown when an OAuth2 error occurs that which can not be sent back
|
|
||||||
# to the client. Defaults to an internal fallback URL.
|
|
||||||
error: https://my-error.app/error
|
|
||||||
# When a user agent requests to logout, it will be redirected to this url afterwards per default.
|
|
||||||
post_logout_redirect: https://my-example.app/logout-successful
|
|
||||||
|
|
||||||
strategies:
|
|
||||||
scope: DEPRECATED_HIERARCHICAL_SCOPE_STRATEGY
|
|
||||||
# You may use JSON Web Tokens as access tokens.
|
|
||||||
#
|
|
||||||
# But seriously. Don't do that. It's not a great idea and has a ton of caveats and subtle security implications. Read more:
|
|
||||||
# -> https://www.ory.sh/docs/hydra/advanced#json-web-tokens
|
|
||||||
#
|
|
||||||
# access_token: jwt
|
|
||||||
|
|
||||||
# configures time to live
|
|
||||||
ttl:
|
|
||||||
# configures how long a user login and consent flow may take. Defaults to 1h.
|
|
||||||
login_consent_request: 1h
|
|
||||||
# configures how long access tokens are valid. Defaults to 1h.
|
|
||||||
access_token: 1h
|
|
||||||
# configures how long refresh tokens are valid. Defaults to 720h. Set to -1 for refresh tokens to never expire.
|
|
||||||
refresh_token: 720h
|
|
||||||
# configures how long id tokens are valid. Defaults to 1h.
|
|
||||||
id_token: 1h
|
|
||||||
# configures how long auth codes are valid. Defaults to 10m.
|
|
||||||
auth_code: 10m
|
|
||||||
|
|
||||||
oauth2:
|
|
||||||
# Set this to true if you want to share error debugging information with your OAuth 2.0 clients.
|
|
||||||
# Keep in mind that debug information is very valuable when dealing with errors, but might also expose database error
|
|
||||||
# codes and similar errors. Defaults to false.
|
|
||||||
expose_internal_errors: true
|
|
||||||
# Configures hashing algorithms. Supports only BCrypt at the moment.
|
|
||||||
hashers:
|
|
||||||
# Configures the BCrypt hashing algorithm used for hashing Client Secrets.
|
|
||||||
bcrypt:
|
|
||||||
# Sets the BCrypt cost. Minimum value is 4 and default value is 10. The higher the value, the more CPU time is being
|
|
||||||
# used to generate hashes.
|
|
||||||
cost: 10
|
|
||||||
pkce:
|
|
||||||
# Set this to true if you want PKCE to be enforced for all clients.
|
|
||||||
enforced: false
|
|
||||||
# Set this to true if you want PKCE to be enforced for public clients.
|
|
||||||
enforced_for_public_clients: false
|
|
||||||
session:
|
|
||||||
# store encrypted data in database, default true
|
|
||||||
encrypt_at_rest: true
|
|
||||||
## refresh_token_rotation
|
|
||||||
# By default Refresh Tokens are rotated and invalidated with each use. See https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.13.2 for more details
|
|
||||||
refresh_token_rotation:
|
|
||||||
#
|
|
||||||
## grace_period
|
|
||||||
#
|
|
||||||
# Set the grace period for refresh tokens to be reused. Such reused tokens will result in multiple refresh tokens being issued.
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
# - 5s
|
|
||||||
# - 1m
|
|
||||||
grace_period: 0s
|
|
||||||
|
|
||||||
# The secrets section configures secrets used for encryption and signing of several systems. All secrets can be rotated,
|
|
||||||
# for more information on this topic navigate to:
|
|
||||||
# -> https://www.ory.sh/docs/hydra/advanced#rotation-of-hmac-token-signing-and-database-and-cookie-encryption-keys
|
|
||||||
secrets:
|
|
||||||
# The system secret must be at least 16 characters long. If none is provided, one will be generated. They key
|
|
||||||
# is used to encrypt sensitive data using AES-GCM (256 bit) and validate HMAC signatures.
|
|
||||||
#
|
|
||||||
# The first item in the list is used for signing and encryption. The whole list is used for verifying signatures
|
|
||||||
# and decryption.
|
|
||||||
system:
|
|
||||||
- this-is-the-primary-secret
|
|
||||||
- this-is-an-old-secret
|
|
||||||
- this-is-another-old-secret
|
|
||||||
# A secret that is used to encrypt cookie sessions. Defaults to secrets.system. It is recommended to use
|
|
||||||
# a separate secret in production.
|
|
||||||
#
|
|
||||||
# The first item in the list is used for signing and encryption. The whole list is used for verifying signatures
|
|
||||||
# and decryption.
|
|
||||||
cookie:
|
|
||||||
- this-is-the-primary-secret
|
|
||||||
- this-is-an-old-secret
|
|
||||||
- this-is-another-old-secret
|
|
||||||
|
|
||||||
# Enables profiling if set. Use "cpu" to enable cpu profiling and "mem" to enable memory profiling. For more details
|
|
||||||
# on profiling, head over to: https://blog.golang.org/profiling-go-programs
|
|
||||||
profiling: cpu
|
|
||||||
# profiling: mem
|
|
||||||
|
|
||||||
# Ory Hydra supports distributed tracing.
|
|
||||||
tracing:
|
|
||||||
# Set this to the tracing backend you wish to use. Currently supports jaeger. If omitted or empty, tracing will
|
|
||||||
# be disabled.
|
|
||||||
provider: jaeger
|
|
||||||
# Specifies the service name to use on the tracer.
|
|
||||||
service_name: Ory Hydra
|
|
||||||
providers:
|
|
||||||
# Configures the jaeger tracing backend.
|
|
||||||
jaeger:
|
|
||||||
# The address of the jaeger-agent where spans should be sent to
|
|
||||||
local_agent_address: 127.0.0.1:6831
|
|
||||||
sampling:
|
|
||||||
# The value passed to the sampler type that has been configured.
|
|
||||||
# Supported values: This is dependant on the sampling strategy used:
|
|
||||||
# - const: 0 or 1 (all or nothing)
|
|
||||||
# - rateLimiting: a constant rate (e.g. setting this to 3 will sample requests with the rate of 3 traces per second)
|
|
||||||
# - probabilistic: a value between 0..1
|
|
||||||
trace_id_ratio: 1.0
|
|
||||||
# The address of jaeger-agent's HTTP sampling server
|
|
||||||
server_url: http://localhost:5778/sampling
|
|
@ -1,7 +1,7 @@
|
|||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
hydra-client:
|
hydra-client:
|
||||||
image: hydra-home # oryd/hydra:v2.2.0
|
image: oryd/hydra:v2.2.0
|
||||||
container_name: hydra-client
|
container_name: hydra-client
|
||||||
environment:
|
environment:
|
||||||
HYDRA_ADMIN_URL: http://hydra:4445
|
HYDRA_ADMIN_URL: http://hydra:4445
|
||||||
@ -9,8 +9,6 @@ services:
|
|||||||
command:
|
command:
|
||||||
- create
|
- create
|
||||||
- oauth2-client
|
- oauth2-client
|
||||||
- --skip-consent
|
|
||||||
- --skip-logout-consent
|
|
||||||
- --skip-tls-verify
|
- --skip-tls-verify
|
||||||
- --name
|
- --name
|
||||||
- test-client
|
- test-client
|
||||||
@ -19,7 +17,7 @@ services:
|
|||||||
- --response-type
|
- --response-type
|
||||||
- id_token,token,code
|
- id_token,token,code
|
||||||
- --grant-type
|
- --grant-type
|
||||||
- implicit,refresh_token,authorization_code
|
- implicit,refresh_token,authorization_code,client_credentials
|
||||||
- --scope
|
- --scope
|
||||||
- openid,profile,email,roles
|
- openid,profile,email,roles
|
||||||
- --token-endpoint-auth-method
|
- --token-endpoint-auth-method
|
||||||
@ -42,10 +40,11 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
hydra:
|
hydra:
|
||||||
container_name: hydra
|
container_name: hydra
|
||||||
image: hydra-home # oryd/hydra:v2.2.0
|
image: oryd/hydra:v2.2.0
|
||||||
environment:
|
environment:
|
||||||
SECRETS_SYSTEM: oc-auth-got-secret
|
SECRETS_SYSTEM: oc-auth-got-secret
|
||||||
LOG_LEAK_SENSITIVE_VALUES: true
|
LOG_LEAK_SENSITIVE_VALUES: true
|
||||||
|
# OAUTH2_TOKEN_HOOK_URL: http://oc-auth:8080/oc/claims
|
||||||
URLS_SELF_ISSUER: http://hydra:4444
|
URLS_SELF_ISSUER: http://hydra:4444
|
||||||
URLS_SELF_PUBLIC: http://hydra:4444
|
URLS_SELF_PUBLIC: http://hydra:4444
|
||||||
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_SCOPES: profile,email,phone,roles
|
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_SCOPES: profile,email,phone,roles
|
||||||
@ -64,7 +63,7 @@ services:
|
|||||||
ldap:
|
ldap:
|
||||||
image: pgarrett/ldap-alpine
|
image: pgarrett/ldap-alpine
|
||||||
container_name: ldap
|
container_name: ldap
|
||||||
volumes:
|
volumes:
|
||||||
- "./ldap.ldif:/ldif/ldap.ldif"
|
- "./ldap.ldif:/ldif/ldap.ldif"
|
||||||
networks:
|
networks:
|
||||||
- hydra-net
|
- hydra-net
|
||||||
@ -74,7 +73,7 @@ services:
|
|||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
networks:
|
networks:
|
||||||
hydra-net:
|
hydra-net:
|
||||||
catalog:
|
catalog:
|
||||||
external: true
|
external: true
|
61
main.go
61
main.go
@ -1,12 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"oc-auth/conf"
|
"oc-auth/conf"
|
||||||
"oc-auth/infrastructure"
|
"oc-auth/infrastructure"
|
||||||
_ "oc-auth/routers"
|
_ "oc-auth/routers"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
oclib "cloud.o-forge.io/core/oc-lib"
|
oclib "cloud.o-forge.io/core/oc-lib"
|
||||||
|
peer "cloud.o-forge.io/core/oc-lib/models/peer"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
"cloud.o-forge.io/core/oc-lib/tools"
|
||||||
beego "github.com/beego/beego/v2/server/web"
|
beego "github.com/beego/beego/v2/server/web"
|
||||||
)
|
)
|
||||||
@ -23,7 +29,8 @@ func main() {
|
|||||||
// Load the right config file
|
// Load the right config file
|
||||||
o := oclib.GetConfLoader()
|
o := oclib.GetConfLoader()
|
||||||
|
|
||||||
conf.GetConfig().PVKPath = o.GetStringDefault("PVK_PATH", "./pvk.pem")
|
conf.GetConfig().PublicKeyPath = o.GetStringDefault("PUBLIC_KEY_PATH", "./pem/public.pem")
|
||||||
|
conf.GetConfig().PrivateKeyPath = o.GetStringDefault("PRIVATE_KEY_PATH", "./pem/private.pem")
|
||||||
conf.GetConfig().ClientSecret = o.GetStringDefault("CLIENT_SECRET", "oc-auth-got-secret")
|
conf.GetConfig().ClientSecret = o.GetStringDefault("CLIENT_SECRET", "oc-auth-got-secret")
|
||||||
|
|
||||||
conf.GetConfig().Auth = o.GetStringDefault("AUTH", "hydra")
|
conf.GetConfig().Auth = o.GetStringDefault("AUTH", "hydra")
|
||||||
@ -40,11 +47,57 @@ func main() {
|
|||||||
conf.GetConfig().LDAPBindPW = o.GetStringDefault("LDAP_BINDPW", "password")
|
conf.GetConfig().LDAPBindPW = o.GetStringDefault("LDAP_BINDPW", "password")
|
||||||
conf.GetConfig().LDAPBaseDN = o.GetStringDefault("LDAP_BASEDN", "dc=example,dc=com")
|
conf.GetConfig().LDAPBaseDN = o.GetStringDefault("LDAP_BASEDN", "dc=example,dc=com")
|
||||||
conf.GetConfig().LDAPRoleBaseDN = o.GetStringDefault("LDAP_ROLE_BASEDN", "ou=AppRoles,dc=example,dc=com")
|
conf.GetConfig().LDAPRoleBaseDN = o.GetStringDefault("LDAP_ROLE_BASEDN", "ou=AppRoles,dc=example,dc=com")
|
||||||
|
err := generateSelfPeer()
|
||||||
Discovery()
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
discovery()
|
||||||
beego.Run()
|
beego.Run()
|
||||||
}
|
}
|
||||||
func Discovery() {
|
|
||||||
|
func generateSelfPeer() error {
|
||||||
|
// TODO check if files at private & public path are set
|
||||||
|
// check if files at private & public path are set
|
||||||
|
if _, err := os.Stat(conf.GetConfig().PrivateKeyPath); errors.Is(err, os.ErrNotExist) {
|
||||||
|
return errors.New("private key path does not exist")
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(conf.GetConfig().PublicKeyPath); errors.Is(err, os.ErrNotExist) {
|
||||||
|
return errors.New("public key path does not exist")
|
||||||
|
}
|
||||||
|
// check if peer already exists
|
||||||
|
p := oclib.Search(nil, strconv.Itoa(peer.SELF.EnumIndex()), oclib.LibDataEnum(oclib.PEER))
|
||||||
|
if len(p.Data) > 0 {
|
||||||
|
// check public key with the one in the database
|
||||||
|
f, err := os.ReadFile(conf.GetConfig().PublicKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// compare the public key from file with the one in the database
|
||||||
|
fmt.Println(string(f), p.Data[0].(*peer.Peer).PublicKey)
|
||||||
|
if !strings.Contains(string(f), p.Data[0].(*peer.Peer).PublicKey) {
|
||||||
|
return errors.New("public key is different from the one in the database")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Println("Creating new peer", strconv.Itoa(peer.SELF.EnumIndex()))
|
||||||
|
// create a new peer
|
||||||
|
o := oclib.GetConfLoader()
|
||||||
|
peer := &peer.Peer{
|
||||||
|
Url: o.GetStringDefault("HOSTNAME", "http://localhost"),
|
||||||
|
AbstractObject: utils.AbstractObject{
|
||||||
|
Name: o.GetStringDefault("NAME", "local"),
|
||||||
|
},
|
||||||
|
PublicKey: conf.GetConfig().PublicKeyPath,
|
||||||
|
State: peer.SELF,
|
||||||
|
}
|
||||||
|
data := oclib.StoreOne(oclib.LibDataEnum(oclib.PEER), peer.Serialize())
|
||||||
|
if data.Err != "" {
|
||||||
|
return errors.New(data.Err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func discovery() {
|
||||||
fmt.Println("Discovered")
|
fmt.Println("Discovered")
|
||||||
api := tools.API{}
|
api := tools.API{}
|
||||||
addPermissions := func(m map[string]interface{}) {
|
addPermissions := func(m map[string]interface{}) {
|
||||||
|
51
pem/private.pem
Normal file
51
pem/private.pem
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
-----END RSA PRIVATE KEY-----
|
13
pem/public.pem
Normal file
13
pem/public.pem
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
-----BEGIN RSA PUBLIC KEY-----
|
||||||
|
MIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR
|
||||||
|
b+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/
|
||||||
|
Bh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa
|
||||||
|
9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp
|
||||||
|
DRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT
|
||||||
|
REyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7
|
||||||
|
ct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5
|
||||||
|
gBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv
|
||||||
|
hKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0
|
||||||
|
iTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV
|
||||||
|
Z2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==
|
||||||
|
-----END RSA PUBLIC KEY-----
|
@ -1 +0,0 @@
|
|||||||
{"namespace":"open-cloud","object":"test-role","relation":"-","subject_id":"oc-auth"}
|
|
@ -7,15 +7,6 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"] = append(beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"],
|
|
||||||
beego.ControllerComments{
|
|
||||||
Method: "Claims",
|
|
||||||
Router: `/claims`,
|
|
||||||
AllowHTTPMethods: []string{"post"},
|
|
||||||
MethodParams: param.Make(),
|
|
||||||
Filters: nil,
|
|
||||||
Params: nil})
|
|
||||||
|
|
||||||
beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"] = append(beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"],
|
beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"] = append(beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"],
|
||||||
beego.ControllerComments{
|
beego.ControllerComments{
|
||||||
Method: "InternalAuthForward",
|
Method: "InternalAuthForward",
|
||||||
|
@ -15,10 +15,8 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ns := beego.NewNamespace("/oc",
|
ns := beego.NewNamespace("/oc",
|
||||||
beego.NSNamespace("/auth",
|
beego.NSInclude(
|
||||||
beego.NSInclude(
|
&controllers.OAuthController{},
|
||||||
&controllers.OAuthController{},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
beego.NSNamespace("/role",
|
beego.NSNamespace("/role",
|
||||||
beego.NSInclude(
|
beego.NSInclude(
|
||||||
|
@ -15,35 +15,10 @@
|
|||||||
},
|
},
|
||||||
"basePath": "/oc",
|
"basePath": "/oc",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/auth/claims": {
|
"/forward": {
|
||||||
"post": {
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"description": "enrich token with claims\n\u003cbr\u003e",
|
|
||||||
"operationId": "OAuthController.Claims",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"in": "body",
|
|
||||||
"name": "body",
|
|
||||||
"description": "The token info",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.Token"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "{string}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/auth/forward": {
|
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"auth"
|
"oc-auth/controllersOAuthController"
|
||||||
],
|
],
|
||||||
"description": "auth forward\n\u003cbr\u003e",
|
"description": "auth forward\n\u003cbr\u003e",
|
||||||
"operationId": "OAuthController.AuthForward",
|
"operationId": "OAuthController.AuthForward",
|
||||||
@ -53,15 +28,6 @@
|
|||||||
"name": "Authorization",
|
"name": "Authorization",
|
||||||
"description": "auth token",
|
"description": "auth token",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
|
||||||
{
|
|
||||||
"in": "body",
|
|
||||||
"name": "body",
|
|
||||||
"description": "The workflow content",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.workflow"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -71,10 +37,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/auth/introspect": {
|
"/introspect": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"auth"
|
"oc-auth/controllersOAuthController"
|
||||||
],
|
],
|
||||||
"description": "introspect token\n\u003cbr\u003e",
|
"description": "introspect token\n\u003cbr\u003e",
|
||||||
"operationId": "OAuthController.Introspection",
|
"operationId": "OAuthController.Introspection",
|
||||||
@ -93,10 +59,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/auth/ldap/login": {
|
"/ldap/login": {
|
||||||
"post": {
|
"post": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"auth"
|
"oc-auth/controllersOAuthController"
|
||||||
],
|
],
|
||||||
"description": "authenticate user\n\u003cbr\u003e",
|
"description": "authenticate user\n\u003cbr\u003e",
|
||||||
"operationId": "OAuthController.Login",
|
"operationId": "OAuthController.Login",
|
||||||
@ -118,10 +84,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/auth/ldap/logout": {
|
"/ldap/logout": {
|
||||||
"delete": {
|
"delete": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"auth"
|
"oc-auth/controllersOAuthController"
|
||||||
],
|
],
|
||||||
"description": "unauthenticate user\n\u003cbr\u003e",
|
"description": "unauthenticate user\n\u003cbr\u003e",
|
||||||
"operationId": "OAuthController.Logout",
|
"operationId": "OAuthController.Logout",
|
||||||
@ -140,31 +106,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/auth/refresh": {
|
|
||||||
"post": {
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"description": "introspect token\n\u003cbr\u003e",
|
|
||||||
"operationId": "OAuthController.Introspection",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"in": "body",
|
|
||||||
"name": "body",
|
|
||||||
"description": "The token info",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.Token"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "{string}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/permission/": {
|
"/permission/": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@ -334,6 +275,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/refresh": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"oc-auth/controllersOAuthController"
|
||||||
|
],
|
||||||
|
"description": "introspect token\n\u003cbr\u003e",
|
||||||
|
"operationId": "OAuthController.Introspection",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "The token info",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.Token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "{string}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/role/": {
|
"/role/": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@ -549,7 +515,7 @@
|
|||||||
},
|
},
|
||||||
"tags": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"name": "auth",
|
"name": "oc-auth/controllersOAuthController",
|
||||||
"description": "Operations about auth\n"
|
"description": "Operations about auth\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -12,28 +12,10 @@ info:
|
|||||||
url: https://www.gnu.org/licenses/agpl-3.0.html
|
url: https://www.gnu.org/licenses/agpl-3.0.html
|
||||||
basePath: /oc
|
basePath: /oc
|
||||||
paths:
|
paths:
|
||||||
/auth/claims:
|
/forward:
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- auth
|
|
||||||
description: |-
|
|
||||||
enrich token with claims
|
|
||||||
<br>
|
|
||||||
operationId: OAuthController.Claims
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: The token info
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.Token'
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: '{string}'
|
|
||||||
/auth/forward:
|
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- auth
|
- oc-auth/controllersOAuthController
|
||||||
description: |-
|
description: |-
|
||||||
auth forward
|
auth forward
|
||||||
<br>
|
<br>
|
||||||
@ -43,19 +25,13 @@ paths:
|
|||||||
name: Authorization
|
name: Authorization
|
||||||
description: auth token
|
description: auth token
|
||||||
type: string
|
type: string
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: The workflow content
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.workflow'
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: '{string}'
|
description: '{string}'
|
||||||
/auth/introspect:
|
/introspect:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- auth
|
- oc-auth/controllersOAuthController
|
||||||
description: |-
|
description: |-
|
||||||
introspect token
|
introspect token
|
||||||
<br>
|
<br>
|
||||||
@ -68,10 +44,10 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: '{string}'
|
description: '{string}'
|
||||||
/auth/ldap/login:
|
/ldap/login:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- auth
|
- oc-auth/controllersOAuthController
|
||||||
description: |-
|
description: |-
|
||||||
authenticate user
|
authenticate user
|
||||||
<br>
|
<br>
|
||||||
@ -86,10 +62,10 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: '{string}'
|
description: '{string}'
|
||||||
/auth/ldap/logout:
|
/ldap/logout:
|
||||||
delete:
|
delete:
|
||||||
tags:
|
tags:
|
||||||
- auth
|
- oc-auth/controllersOAuthController
|
||||||
description: |-
|
description: |-
|
||||||
unauthenticate user
|
unauthenticate user
|
||||||
<br>
|
<br>
|
||||||
@ -102,24 +78,6 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: '{string}'
|
description: '{string}'
|
||||||
/auth/refresh:
|
|
||||||
post:
|
|
||||||
tags:
|
|
||||||
- auth
|
|
||||||
description: |-
|
|
||||||
introspect token
|
|
||||||
<br>
|
|
||||||
operationId: OAuthController.Introspection
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: The token info
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.Token'
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: '{string}'
|
|
||||||
/permission/:
|
/permission/:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -246,6 +204,24 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: '{auth} string'
|
description: '{auth} string'
|
||||||
|
/refresh:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- oc-auth/controllersOAuthController
|
||||||
|
description: |-
|
||||||
|
introspect token
|
||||||
|
<br>
|
||||||
|
operationId: OAuthController.Introspection
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: The token info
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.Token'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: '{string}'
|
||||||
/role/:
|
/role/:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -407,7 +383,7 @@ definitions:
|
|||||||
title: workflow
|
title: workflow
|
||||||
type: object
|
type: object
|
||||||
tags:
|
tags:
|
||||||
- name: auth
|
- name: oc-auth/controllersOAuthController
|
||||||
description: |
|
description: |
|
||||||
Operations about auth
|
Operations about auth
|
||||||
- name: role
|
- name: role
|
||||||
|
Loading…
Reference in New Issue
Block a user