BAHAMAS
This commit is contained in:
parent
7198c40d30
commit
d87883b57f
@ -1,5 +1,8 @@
|
||||
FROM golang:alpine as builder
|
||||
|
||||
ARG HOSTNAME=http://localhost
|
||||
ARG NAME=local
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
Binary file not shown.
@ -3,7 +3,8 @@ package conf
|
||||
import "sync"
|
||||
|
||||
type Config struct {
|
||||
PVKPath string
|
||||
PublicKeyPath string
|
||||
PrivateKeyPath string
|
||||
|
||||
LDAPEndpoints string
|
||||
LDAPBindDN string
|
||||
|
@ -1,18 +1,16 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"oc-auth/infrastructure"
|
||||
auth_connectors "oc-auth/infrastructure/auth_connector"
|
||||
"oc-auth/infrastructure/claims"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
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"
|
||||
)
|
||||
|
||||
@ -78,22 +76,6 @@ func (o *OAuthController) LoginLDAP() {
|
||||
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
|
||||
// @Description introspect token
|
||||
// @Param body body models.Token true "The token info"
|
||||
@ -126,6 +108,7 @@ func (o *OAuthController) Introspect() {
|
||||
} else {
|
||||
reqToken = splitToken[1]
|
||||
}
|
||||
|
||||
token, err := infrastructure.GetAuthConnector().Introspect(reqToken)
|
||||
if err != nil || !token {
|
||||
o.Data["json"] = err
|
||||
@ -134,37 +117,55 @@ func (o *OAuthController) Introspect() {
|
||||
o.ServeJSON()
|
||||
}
|
||||
|
||||
var whitelist = []string{
|
||||
"/login",
|
||||
"/refresh",
|
||||
"/introspect",
|
||||
}
|
||||
|
||||
// @Title AuthForward
|
||||
// @Description auth forward
|
||||
// @Param Authorization header string false "auth token"
|
||||
// @Param body body models.workflow true "The workflow content"
|
||||
// @Success 200 {string}
|
||||
// @router /forward [get]
|
||||
func (o *OAuthController) InternalAuthForward() {
|
||||
fmt.Println("InternalAuthForward")
|
||||
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 ")
|
||||
if len(splitToken) < 2 {
|
||||
reqToken = ""
|
||||
} else {
|
||||
reqToken = splitToken[1]
|
||||
}
|
||||
origin, publicKey, external := o.extractOrigin()
|
||||
if reqToken != "" && !o.checkAuthForward(reqToken, publicKey) && origin != "" {
|
||||
fmt.Println("Unauthorized", origin, reqToken)
|
||||
origin, publicKey, _ := o.extractOrigin()
|
||||
if !infrastructure.GetAuthConnector().CheckAuthForward( //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.ServeJSON()
|
||||
return
|
||||
}
|
||||
token, err := infrastructure.GetAuthConnector().Introspect(reqToken, &http.Cookie{
|
||||
isToken, err := infrastructure.GetAuthConnector().Introspect(reqToken, &http.Cookie{
|
||||
Name: "csrf_token",
|
||||
Value: o.XSRFToken(),
|
||||
}) // may be a problem... we should check if token is valid on our side
|
||||
// prefers a refresh token call
|
||||
if err != nil || external {
|
||||
fmt.Println("Unauthorized 2", err, external) // error
|
||||
fmt.Println("InternalAuthForward", isToken, err)
|
||||
if err != nil || !isToken {
|
||||
o.Ctx.ResponseWriter.WriteHeader(401)
|
||||
} else if token && !external { // redirect to login
|
||||
o.Data["json"] = token
|
||||
}
|
||||
o.ServeJSON()
|
||||
}
|
||||
@ -176,50 +177,25 @@ func (o *OAuthController) extractOrigin() (string, string, bool) {
|
||||
if origin == "" {
|
||||
origin = o.Ctx.Request.Header.Get("Origin")
|
||||
}
|
||||
idLoc, loc := static.GetMyLocalJsonPeer()
|
||||
if origin != "" { // is external
|
||||
peer := oclib.Search(nil, origin, oclib.LibDataEnum(oclib.PEER))
|
||||
if peer.Code != 200 {
|
||||
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]
|
||||
if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") || idLoc == p.GetID() {
|
||||
p := peer.Data[0].(*model.Peer)
|
||||
publicKey = p.PublicKey
|
||||
origin = p.Url
|
||||
if origin != "" { // is external
|
||||
if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") || p.State == model.SELF {
|
||||
external = false
|
||||
}
|
||||
publicKey = p.(*model.Peer).PublicKey
|
||||
} else {
|
||||
external = false
|
||||
publicKey = loc["public_key"].(string)
|
||||
}
|
||||
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'
|
||||
|
||||
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:
|
||||
image: 'oc-auth:latest'
|
||||
ports:
|
||||
- 8094:8080
|
||||
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:
|
||||
PVK_PATH: /etc/oc/pvk.pem
|
||||
LDAP_ENDPOINTS: ldap:389
|
||||
LDAP_BINDDN: cn=admin,dc=example,dc=com
|
||||
LDAP_BINDPW: password
|
||||
@ -15,6 +47,8 @@ services:
|
||||
LDAP_ROLE_BASEDN: "ou=AppRoles,dc=example,dc=com"
|
||||
networks:
|
||||
- catalog
|
||||
volumes:
|
||||
- ./pem:/etc/oc/pem
|
||||
networks:
|
||||
catalog:
|
||||
external: true
|
@ -3,5 +3,7 @@
|
||||
"MONGO_DATABASE":"DC_myDC",
|
||||
"NATS_URL": "nats://nats:4222",
|
||||
"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
|
||||
|
||||
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/nats-io/nats.go v1.37.0
|
||||
github.com/ory/hydra-client-go v1.11.8
|
||||
github.com/smartystreets/goconvey v1.7.2
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/oauth2 v0.23.0
|
||||
)
|
||||
|
||||
@ -69,7 +70,6 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
go.uber.org/atomic v1.9.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/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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/common v0.60.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/rs/zerolog v1.33.0 // 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-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-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=
|
||||
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=
|
||||
@ -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.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
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/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
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,13 +12,15 @@ type AuthConnector interface {
|
||||
Logout(token string, cookies ...*http.Cookie) (*Token, error)
|
||||
Introspect(token string, cookie ...*http.Cookie) (bool, error)
|
||||
Refresh(token *Token) (*Token, error)
|
||||
CheckAuthForward(reqToken string, publicKey string, host string, method string, forward string) bool
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
Active bool `json:"active"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Challenge string `json:"challenge"`
|
||||
TokenType string `json:"token_type"`
|
||||
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package auth_connectors
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -8,10 +9,12 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"oc-auth/conf"
|
||||
"oc-auth/infrastructure/claims"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -81,10 +84,18 @@ func (a HydraConnector) challenge(username string, url string, challenge string,
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil || !isValid {
|
||||
return nil, err
|
||||
}
|
||||
_, err = a.Logout(token.AccessToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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...)
|
||||
}
|
||||
|
||||
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 {
|
||||
resp, err := a.Caller.CallGet(a.getPath(true, false), "/clients")
|
||||
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) {
|
||||
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,
|
||||
"login", cookies...)
|
||||
if err != nil || redirect == nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
// problem with consent THERE we need to accept the consent challenge && get the token
|
||||
url := ""
|
||||
resp, err := a.Caller.CallRaw(http.MethodGet, a.urlFormat(redirect.RedirectTo, a.getPath(false, true)), "", map[string]interface{}{},
|
||||
_, err = a.Caller.CallRaw(http.MethodGet, a.urlFormat(redirect.RedirectTo, a.getPath(false, true)), "", map[string]interface{}{},
|
||||
"application/json", true, cookies...)
|
||||
fmt.Println(err)
|
||||
if err != nil {
|
||||
s := strings.Split(err.Error(), "\"")
|
||||
if len(s) > 1 && strings.Contains(s[1], "access_token") {
|
||||
url = s[1]
|
||||
err = nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
url = resp.Request.Response.Request.URL.Fragment
|
||||
}
|
||||
token := a.extractTokenFromFragment(url)
|
||||
fmt.Println(url, token)
|
||||
if token == nil || token.AccessToken == "" {
|
||||
return nil, errors.New("no token found")
|
||||
token := &Token{
|
||||
Username: username,
|
||||
}
|
||||
token.Challenge = challenge
|
||||
token.Active = true
|
||||
token.Username = username
|
||||
fmt.Println(token)
|
||||
urls := url.Values{}
|
||||
urls.Add("client_id", clientID)
|
||||
urls.Add("client_secret", conf.GetConfig().ClientSecret)
|
||||
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
|
||||
}
|
||||
|
||||
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"
|
||||
urls := url.Values{}
|
||||
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) {
|
||||
// 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
|
||||
access := strings.Split(token, ".")
|
||||
if len(access) > 2 {
|
||||
token = strings.Join(access[0:2], ".")
|
||||
}
|
||||
urls := url.Values{}
|
||||
urls.Add("token", token)
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import "oc-auth/conf"
|
||||
|
||||
// Tokenizer interface
|
||||
type ClaimService interface {
|
||||
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
|
||||
@ -16,3 +18,11 @@ type SessionClaims struct {
|
||||
type Claims struct {
|
||||
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
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"oc-auth/conf"
|
||||
"oc-auth/infrastructure/perms_connectors"
|
||||
"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) {
|
||||
fmt.Println("DecodeSignature", host)
|
||||
hashed := sha256.Sum256([]byte(host))
|
||||
// get public key into a variable
|
||||
spkiBlock, _ := pem.Decode([]byte(publicKey))
|
||||
key, _ := x509.ParsePKCS1PublicKey(spkiBlock.Bytes)
|
||||
err := rsa.VerifyPKCS1v15(key, crypto.SHA256, hashed[:], []byte(signature))
|
||||
spkiBlock, _ := pem.Decode([]byte(publicKey)) // get public key into a variable
|
||||
err := VerifyDefault(hashed[:], spkiBlock.Bytes, signature)
|
||||
if err != nil {
|
||||
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) {
|
||||
fmt.Println("encodeSignature", host)
|
||||
hashed := sha256.Sum256([]byte(host))
|
||||
// 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 {
|
||||
return "", err
|
||||
}
|
||||
privateKey := string(content)
|
||||
spkiBlock, _ := pem.Decode([]byte(privateKey))
|
||||
key, _ := x509.ParsePKCS1PrivateKey(spkiBlock.Bytes)
|
||||
signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hashed[:])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(signature), nil
|
||||
return SignDefault(hashed[:], spkiBlock.Bytes)
|
||||
}
|
||||
|
||||
func (h HydraClaims) DecodeClaimsInToken(host string, method string, forward string, sessionClaims map[string]interface{}, publicKey string) (bool, error) {
|
||||
if sessionClaims["id_token"] == nil || sessionClaims["access_token"] == nil {
|
||||
return false, errors.New("invalid session claims")
|
||||
func (h HydraClaims) DecodeClaimsInToken(host string, method string, forward string, sessionClaims Claims, publicKey string) (bool, error) {
|
||||
idTokenClaims := sessionClaims.Session.IDToken
|
||||
if idTokenClaims["signature"] == nil {
|
||||
return false, errors.New("no signature found")
|
||||
}
|
||||
idTokenClaims := sessionClaims["id_token"].(map[string]interface{})
|
||||
signature := idTokenClaims["signature"].(string)
|
||||
if ok, err := h.DecodeSignature(host, signature, publicKey); !ok {
|
||||
return false, err
|
||||
}
|
||||
claims := sessionClaims["access_token"].(map[string]interface{})
|
||||
claims := sessionClaims.Session.AccessToken
|
||||
path := strings.ReplaceAll(forward, "http://"+host, "")
|
||||
splittedPath := strings.Split(path, "/")
|
||||
for m, p := range claims {
|
||||
@ -114,6 +106,8 @@ func (h HydraClaims) AddClaimsToToken(userId string, host string) Claims {
|
||||
if err != nil {
|
||||
return claims
|
||||
}
|
||||
claims.Session.AccessToken = make(map[string]interface{})
|
||||
claims.Session.IDToken = make(map[string]interface{})
|
||||
for _, perm := range perms {
|
||||
key, err := h.generateKey(perm.Relation, perm.Object)
|
||||
if err != nil {
|
||||
@ -127,7 +121,6 @@ func (h HydraClaims) AddClaimsToToken(userId string, host string) Claims {
|
||||
}
|
||||
claims.Session.IDToken["signature"] = sign
|
||||
return claims
|
||||
|
||||
}
|
||||
|
||||
// add signature in the token MISSING
|
||||
|
@ -9,10 +9,6 @@ import (
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
var t = map[string]claims.ClaimService{
|
||||
"hydra": claims.HydraClaims{},
|
||||
}
|
||||
|
||||
var a = map[string]auth_connectors.AuthConnector{
|
||||
"hydra": auth_connectors.HydraConnector{
|
||||
Caller: tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{}),
|
||||
@ -28,5 +24,5 @@ func GetPermissionConnector() perms_connectors.PermConnector {
|
||||
}
|
||||
|
||||
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"
|
||||
services:
|
||||
hydra-client:
|
||||
image: hydra-home # oryd/hydra:v2.2.0
|
||||
image: oryd/hydra:v2.2.0
|
||||
container_name: hydra-client
|
||||
environment:
|
||||
HYDRA_ADMIN_URL: http://hydra:4445
|
||||
@ -9,8 +9,6 @@ services:
|
||||
command:
|
||||
- create
|
||||
- oauth2-client
|
||||
- --skip-consent
|
||||
- --skip-logout-consent
|
||||
- --skip-tls-verify
|
||||
- --name
|
||||
- test-client
|
||||
@ -19,7 +17,7 @@ services:
|
||||
- --response-type
|
||||
- id_token,token,code
|
||||
- --grant-type
|
||||
- implicit,refresh_token,authorization_code
|
||||
- implicit,refresh_token,authorization_code,client_credentials
|
||||
- --scope
|
||||
- openid,profile,email,roles
|
||||
- --token-endpoint-auth-method
|
||||
@ -42,10 +40,11 @@ services:
|
||||
retries: 10
|
||||
hydra:
|
||||
container_name: hydra
|
||||
image: hydra-home # oryd/hydra:v2.2.0
|
||||
image: oryd/hydra:v2.2.0
|
||||
environment:
|
||||
SECRETS_SYSTEM: oc-auth-got-secret
|
||||
LOG_LEAK_SENSITIVE_VALUES: true
|
||||
# OAUTH2_TOKEN_HOOK_URL: http://oc-auth:8080/oc/claims
|
||||
URLS_SELF_ISSUER: http://hydra:4444
|
||||
URLS_SELF_PUBLIC: http://hydra:4444
|
||||
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_SCOPES: profile,email,phone,roles
|
61
main.go
61
main.go
@ -1,12 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"oc-auth/conf"
|
||||
"oc-auth/infrastructure"
|
||||
_ "oc-auth/routers"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
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"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
@ -23,7 +29,8 @@ func main() {
|
||||
// Load the right config file
|
||||
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().Auth = o.GetStringDefault("AUTH", "hydra")
|
||||
@ -40,11 +47,57 @@ func main() {
|
||||
conf.GetConfig().LDAPBindPW = o.GetStringDefault("LDAP_BINDPW", "password")
|
||||
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")
|
||||
|
||||
Discovery()
|
||||
err := generateSelfPeer()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
discovery()
|
||||
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")
|
||||
api := tools.API{}
|
||||
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() {
|
||||
|
||||
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.ControllerComments{
|
||||
Method: "InternalAuthForward",
|
||||
|
@ -15,11 +15,9 @@ import (
|
||||
|
||||
func init() {
|
||||
ns := beego.NewNamespace("/oc",
|
||||
beego.NSNamespace("/auth",
|
||||
beego.NSInclude(
|
||||
&controllers.OAuthController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("/role",
|
||||
beego.NSInclude(
|
||||
&controllers.RoleController{},
|
||||
|
@ -15,35 +15,10 @@
|
||||
},
|
||||
"basePath": "/oc",
|
||||
"paths": {
|
||||
"/auth/claims": {
|
||||
"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": {
|
||||
"/forward": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"auth"
|
||||
"oc-auth/controllersOAuthController"
|
||||
],
|
||||
"description": "auth forward\n\u003cbr\u003e",
|
||||
"operationId": "OAuthController.AuthForward",
|
||||
@ -53,15 +28,6 @@
|
||||
"name": "Authorization",
|
||||
"description": "auth token",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "The workflow content",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.workflow"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -71,10 +37,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/introspect": {
|
||||
"/introspect": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"auth"
|
||||
"oc-auth/controllersOAuthController"
|
||||
],
|
||||
"description": "introspect token\n\u003cbr\u003e",
|
||||
"operationId": "OAuthController.Introspection",
|
||||
@ -93,10 +59,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/ldap/login": {
|
||||
"/ldap/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"auth"
|
||||
"oc-auth/controllersOAuthController"
|
||||
],
|
||||
"description": "authenticate user\n\u003cbr\u003e",
|
||||
"operationId": "OAuthController.Login",
|
||||
@ -118,10 +84,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/ldap/logout": {
|
||||
"/ldap/logout": {
|
||||
"delete": {
|
||||
"tags": [
|
||||
"auth"
|
||||
"oc-auth/controllersOAuthController"
|
||||
],
|
||||
"description": "unauthenticate user\n\u003cbr\u003e",
|
||||
"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/": {
|
||||
"get": {
|
||||
"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/": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@ -549,7 +515,7 @@
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "auth",
|
||||
"name": "oc-auth/controllersOAuthController",
|
||||
"description": "Operations about auth\n"
|
||||
},
|
||||
{
|
||||
|
@ -12,28 +12,10 @@ info:
|
||||
url: https://www.gnu.org/licenses/agpl-3.0.html
|
||||
basePath: /oc
|
||||
paths:
|
||||
/auth/claims:
|
||||
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:
|
||||
/forward:
|
||||
get:
|
||||
tags:
|
||||
- auth
|
||||
- oc-auth/controllersOAuthController
|
||||
description: |-
|
||||
auth forward
|
||||
<br>
|
||||
@ -43,19 +25,13 @@ paths:
|
||||
name: Authorization
|
||||
description: auth token
|
||||
type: string
|
||||
- in: body
|
||||
name: body
|
||||
description: The workflow content
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/models.workflow'
|
||||
responses:
|
||||
"200":
|
||||
description: '{string}'
|
||||
/auth/introspect:
|
||||
/introspect:
|
||||
get:
|
||||
tags:
|
||||
- auth
|
||||
- oc-auth/controllersOAuthController
|
||||
description: |-
|
||||
introspect token
|
||||
<br>
|
||||
@ -68,10 +44,10 @@ paths:
|
||||
responses:
|
||||
"200":
|
||||
description: '{string}'
|
||||
/auth/ldap/login:
|
||||
/ldap/login:
|
||||
post:
|
||||
tags:
|
||||
- auth
|
||||
- oc-auth/controllersOAuthController
|
||||
description: |-
|
||||
authenticate user
|
||||
<br>
|
||||
@ -86,10 +62,10 @@ paths:
|
||||
responses:
|
||||
"200":
|
||||
description: '{string}'
|
||||
/auth/ldap/logout:
|
||||
/ldap/logout:
|
||||
delete:
|
||||
tags:
|
||||
- auth
|
||||
- oc-auth/controllersOAuthController
|
||||
description: |-
|
||||
unauthenticate user
|
||||
<br>
|
||||
@ -102,24 +78,6 @@ paths:
|
||||
responses:
|
||||
"200":
|
||||
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/:
|
||||
get:
|
||||
tags:
|
||||
@ -246,6 +204,24 @@ paths:
|
||||
responses:
|
||||
"200":
|
||||
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/:
|
||||
get:
|
||||
tags:
|
||||
@ -407,7 +383,7 @@ definitions:
|
||||
title: workflow
|
||||
type: object
|
||||
tags:
|
||||
- name: auth
|
||||
- name: oc-auth/controllersOAuthController
|
||||
description: |
|
||||
Operations about auth
|
||||
- name: role
|
||||
|
Loading…
Reference in New Issue
Block a user