55 Commits

Author SHA1 Message Date
mr
484154a48d auth 2026-02-10 10:13:33 +01:00
mr
af0a8cb117 oc-auth 2026-02-10 09:39:13 +01:00
mr
eb6dee0c4d lightest tag 2026-02-09 09:42:19 +01:00
mr
b8b0743af5 dockerfile scratch 2026-02-09 09:01:09 +01:00
mr
28c08d0873 remove git add 2026-02-09 08:53:05 +01:00
mr
eef21ad537 publish ci 2026-02-05 12:01:17 +01:00
mr
492aff13a3 publish-registry ci 2026-02-05 11:59:43 +01:00
mr
627058fcab publish-registry 2026-02-05 11:55:09 +01:00
mr
1acd2ea634 LDAPRoleBaseDN 2026-02-04 11:28:03 +01:00
mr
a897f5aa75 user not found 2026-02-04 11:06:38 +01:00
mr
64b8da67f2 inspect conn 2026-02-04 10:59:01 +01:00
mr
5512cc76c3 users 2026-02-04 10:47:40 +01:00
mr
7d3cb1af61 security injection appname 2026-02-04 09:42:20 +01:00
mr
b18718cb47 compact conf 2026-02-03 16:20:25 +01:00
mr
3f245b3f02 reversuserldap 2026-02-03 10:04:10 +01:00
mr
980fd50cf5 oclib-debug 2026-02-03 08:50:06 +01:00
mr
02476ca07d uid=admin,ou=users,dc=opencloud,dc=com 2026-02-02 11:02:27 +01:00
mr
f56b947e1f LDAP_USER_BASEDN 2026-02-02 10:36:31 +01:00
mr
0e86777fd3 ok 2026-02-02 10:09:45 +01:00
mr
6b9e21b929 test 2026-02-02 10:00:44 +01:00
mr
365d62a64e User Base DN 2026-01-26 11:05:38 +01:00
mr
076dca0a1d new oclib 2026-01-26 10:38:39 +01:00
mr
e1cb9b3a08 debug recovery 2026-01-26 09:48:21 +01:00
mr
7127dc9010 prospect failing binding 2026-01-26 09:17:35 +01:00
mr
1f4b25c594 test 2026-01-23 11:09:31 +01:00
mr
f93371e449 ldap -> auth 2026-01-23 10:22:14 +01:00
mr
013c6969c5 6b12aa1713c79983dc99e489acb2d4e0da641b7d 2026-01-23 10:04:59 +01:00
mr
403deaf65b test 2026-01-23 09:49:46 +01:00
mr
9d0b720231 new oclib 2026-01-23 09:40:38 +01:00
mr
932e40190d CLUSTERNAME in makefile 2026-01-20 11:20:16 +01:00
mr
f226866fc7 dockerfile 2026-01-08 10:41:02 +01:00
mr
b154532a1a update 2025-11-20 16:31:10 +01:00
mr
a546c1220e gitignore 2025-11-13 09:57:40 +01:00
fb3366328b Ajouter .gitattributes 2025-11-01 16:38:21 +01:00
mr
75857dc125 oclib 2025-06-24 16:57:35 +02:00
mr
e7ff288972 nats push 2025-06-24 09:14:59 +02:00
mr
d83208be52 deploy adjust 2025-06-16 09:11:21 +02:00
mr
3d42ce6820 auth 2025-04-01 10:16:26 +02:00
mr
5ca9a10d14 launch mode 2025-03-06 09:46:13 +01:00
mr
a480c9b8a0 neo oclib 2025-02-21 11:24:03 +01:00
mr
6a6fe77c30 traefik 2025-02-19 12:02:44 +01:00
mr
2f8524af01 oclib update 2025-02-18 15:06:32 +01:00
mr
b684ba841f Correction 2025-02-18 09:20:13 +01:00
mr
37a0ceddf4 adjust in docker conf 2025-02-18 08:52:47 +01:00
mr
b18b82ea8c Merge branch 'feature/order' into main 2025-02-18 08:35:12 +01:00
mr
9bb08fc961 Merge branch 'feature/payment' into main 2025-02-13 10:32:46 +01:00
mr
cf08618f83 neo oclib 2025-02-13 10:28:36 +01:00
mr
0989aeb979 neo oc-lib 2025-02-06 08:56:30 +01:00
mr
8f4e33ab80 neo oc lib 2025-02-05 08:43:17 +01:00
plm
8df956bdcd Handling clientID/password from k8s secret 2025-01-22 15:23:18 +01:00
plm
776aac5d43 Fix oc-auth for k8s integration 2025-01-21 15:23:45 +01:00
mr
b84c2ef353 workin oc-auth 2025-01-17 17:24:08 +01:00
plm
27e2df2310 Support CORS 2025-01-15 11:38:12 +01:00
plm
939c8cdd67 Updating go.sum 2025-01-08 21:55:45 +01:00
plm
2a794518d5 upgrading oc-lib 2025-01-08 21:44:50 +01:00
35 changed files with 768 additions and 422 deletions

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
# Force Go as the main language
*.go linguist-detectable=true
* linguist-language=Go

2
.gitignore vendored
View File

@@ -20,4 +20,4 @@
# Go workspace file
go.work
env.env

View File

@@ -10,11 +10,6 @@ RUN go mod download
FROM golang:alpine AS builder
ARG HOSTNAME=http://localhost
ARG NAME=local
RUN apk add git
RUN go install github.com/beego/bee/v2@latest
WORKDIR /oc-auth

View File

@@ -6,6 +6,14 @@ build: clean
run:
bee run -gendoc=true -downdoc=true
purge:
lsof -t -i:8094 | xargs kill | true
run-dev:
bee generate routers && bee run -gendoc=true -downdoc=true -runmode=prod
dev: purge run-dev
debug:
bee run -downdebug -gendebug
@@ -13,15 +21,22 @@ clean:
rm -rf oc-auth oc-auth.tar.gz
docker:
DOCKER_BUILDKIT=1 docker build -t oc/oc-auth:0.0.1 -f Dockerfile .
docker tag oc/oc-auth:0.0.1 oc/oc-auth:latest
DOCKER_BUILDKIT=1 docker build -t oc-auth -f Dockerfile . --build-arg=HOST=$(HOST)
docker tag oc-auth opencloudregistry/oc-auth:latest
publish-kind:
kind load docker-image oc/oc-auth:0.0.1 --name opencloud
kind load docker-image opencloudregistry/oc-auth:latest --name $(CLUSTER_NAME) | true
publish-registry:
@echo "TODO"
docker push opencloudregistry/oc-auth:latest
all: docker publish-kind publish-registry
docker-deploy:
docker compose up -d
.PHONY: build run clean docker publish-kind publish-registry
run-docker: docker publish-kind publish-registry docker-deploy
all: docker publish-kind
ci: docker publish-registry
.PHONY: build run clean docker publish-kind publish-registry

View File

@@ -7,7 +7,58 @@ To build :
bee generate routers
bee run -gendoc=true -downdoc=true
OR
make dev
If default Swagger page is displayed instead of tyour api, change url in swagger/index.html file to :
url: "swagger.json"
Browser UI Hydra API
1. Click "Login"
2. Redirect auth
/oauth2/auth
login challenge
3. Login UI
(credentials)
accept login
consent challenge
4. CALL API
fetch peer / roles
peer, permissions
5. Accept consent
+ custom claims
redirect w/ code
6. Exchange code
for token /oauth2/token
7. JWT access_token
(signed + enriched)
8. API call with Bearer token

View File

@@ -1,9 +1,7 @@
{
"port": 8080,
"MONGO_URL":"mongodb://localhost:27017/",
"MONGO_DATABASE":"DC_myDC",
"natsurl":"http://localhost:4080",
"login":"admin",
"password":"admin",
"oidcserver":"http://localhost:8080"
"NATS_URL": "nats://localhost:4222",
"LDAP_ENDPOINTS": "localhost:390",
"port": 8094
}

View File

@@ -1,5 +1,5 @@
appname = oc-auth
httpport = 8080
httpport = 8094
runmode = dev
autorender = false
copyrequestbody = true

View File

@@ -3,6 +3,7 @@ package conf
import "sync"
type Config struct {
SourceMode string
AdminRole string
PublicKeyPath string
PrivateKeyPath string
@@ -11,18 +12,25 @@ type Config struct {
LDAPBindDN string
LDAPBindPW string
LDAPBaseDN string
LDAPUserBaseDN string
LDAPRoleBaseDN string
ClientSecret string
ClientSecret string
OAuth2ClientSecretName string
OAuth2ClientSecretNamespace string
Auth string
AuthConnectPublicHost string
AuthConnectorHost string
AuthConnectorPort int
AuthConnectorAdminPort int
AuthConnectorAdminPort string
PermissionConnectorHost string
PermissionConnectorPort int
PermissionConnectorAdminPort int
PermissionConnectorWriteHost string
PermissionConnectorReadHost string
PermissionConnectorPort string
PermissionConnectorAdminPort string
Local bool
}
var instance *Config

View File

@@ -19,7 +19,8 @@ type GroupController struct {
func (o *GroupController) Post() {
// store and return Id or post with UUID
id := o.Ctx.Input.Param(":id")
group, code, err := infrastructure.GetPermissionConnector().CreateGroup(id)
clientID := ExtractClient(*o.Ctx.Request)
group, code, err := infrastructure.GetPermissionConnector(clientID).CreateGroup(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -44,7 +45,8 @@ func (o *GroupController) Post() {
// @router /user/:id [get]
func (o *GroupController) GetByUser() {
id := o.Ctx.Input.Param(":id")
group, err := infrastructure.GetPermissionConnector().GetGroupByUser(id)
clientID := ExtractClient(*o.Ctx.Request)
group, err := infrastructure.GetPermissionConnector(clientID).GetGroupByUser(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -67,7 +69,8 @@ func (o *GroupController) GetByUser() {
// @Success 200 {group} string
// @router / [get]
func (o *GroupController) GetAll() {
group, err := infrastructure.GetPermissionConnector().GetGroup("")
clientID := ExtractClient(*o.Ctx.Request)
group, err := infrastructure.GetPermissionConnector(clientID).GetGroup("")
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -92,7 +95,8 @@ func (o *GroupController) GetAll() {
// @router /:id [get]
func (o *GroupController) Get() {
id := o.Ctx.Input.Param(":id")
group, err := infrastructure.GetPermissionConnector().GetGroup(id)
clientID := ExtractClient(*o.Ctx.Request)
group, err := infrastructure.GetPermissionConnector(clientID).GetGroup(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -117,7 +121,8 @@ func (o *GroupController) Get() {
// @router /:id [delete]
func (o *GroupController) Delete() {
id := o.Ctx.Input.Param(":id")
group, code, err := infrastructure.GetPermissionConnector().DeleteGroup(id)
clientID := ExtractClient(*o.Ctx.Request)
group, code, err := infrastructure.GetPermissionConnector(clientID).DeleteGroup(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -140,7 +145,8 @@ func (o *GroupController) Delete() {
// @Success 200 {string} delete success!
// @router /clear [delete]
func (o *GroupController) Clear() {
group, code, err := infrastructure.GetPermissionConnector().DeleteGroup("")
clientID := ExtractClient(*o.Ctx.Request)
group, code, err := infrastructure.GetPermissionConnector(clientID).DeleteGroup("")
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -167,7 +173,8 @@ func (o *GroupController) Clear() {
func (o *GroupController) Bind() {
user_id := o.Ctx.Input.Param(":user_id")
group_id := o.Ctx.Input.Param(":group_id")
group, code, err := infrastructure.GetPermissionConnector().BindGroup(user_id, group_id)
clientID := ExtractClient(*o.Ctx.Request)
group, code, err := infrastructure.GetPermissionConnector(clientID).BindGroup(user_id, group_id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -187,14 +194,15 @@ func (o *GroupController) Bind() {
// @Title UnBind
// @Description unbind the group to user
// @Param group_id path string true "The group_id you want to unbind"
// @Param user_id path string true "The group_id you want to unbind"
// @Param group_id path string true "The user_id you want to unbind"
// @Success 200 {string} bind success!
// @router /:user_id/:group_id [delete]
func (o *GroupController) UnBind() {
user_id := o.Ctx.Input.Param(":user_id")
group_id := o.Ctx.Input.Param(":group_id")
group, code, err := infrastructure.GetPermissionConnector().UnBindGroup(user_id, group_id)
clientID := ExtractClient(*o.Ctx.Request)
group, code, err := infrastructure.GetPermissionConnector(clientID).UnBindGroup(user_id, group_id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,

View File

@@ -1,15 +1,20 @@
package controllers
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"oc-auth/conf"
"oc-auth/infrastructure"
auth_connectors "oc-auth/infrastructure/auth_connector"
"oc-auth/infrastructure/claims"
"regexp"
"strings"
"time"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/models/peer"
model "cloud.o-forge.io/core/oc-lib/models/peer"
beego "github.com/beego/beego/v2/server/web"
)
@@ -22,10 +27,12 @@ type OAuthController struct {
// @Title Logout
// @Description unauthenticate user
// @Param Authorization header string false "auth token"
// @Param client_id query string true "the client_id you want to get"
// @Success 200 {string}
// @router /ldap/logout [delete]
func (o *OAuthController) LogOutLDAP() {
// @router /logout [delete]
func (o *OAuthController) LogOut() {
// authorize user
clientID := o.Ctx.Input.Query("client_id")
reqToken := o.Ctx.Request.Header.Get("Authorization")
splitToken := strings.Split(reqToken, "Bearer ")
if len(splitToken) < 2 {
@@ -36,11 +43,15 @@ func (o *OAuthController) LogOutLDAP() {
var res auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res)
token, err := infrastructure.GetAuthConnector().Logout(reqToken)
if err != nil || token == nil {
o.Data["json"] = err
if !conf.GetConfig().Local {
token, err := infrastructure.GetAuthConnector().Logout(clientID, reqToken)
if err != nil || token == nil {
o.Data["json"] = err
} else {
o.Data["json"] = token
}
} else {
o.Data["json"] = token
o.Data["json"] = reqToken
}
o.ServeJSON()
}
@@ -48,30 +59,65 @@ func (o *OAuthController) LogOutLDAP() {
// @Title Login
// @Description authenticate user
// @Param body body models.workflow true "The workflow content"
// @Param client_id query string true "the client_id you want to get"
// @Success 200 {string}
// @router /ldap/login [post]
func (o *OAuthController) LoginLDAP() {
// @router /login [post]
func (o *OAuthController) Login() {
// authorize user
clientID := o.Ctx.Input.Query("client_id")
var res auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res)
ldap := auth_connectors.New()
found, err := ldap.Authenticate(o.Ctx.Request.Context(), res.Username, res.Password)
if err != nil || !found {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
o.ServeJSON()
return
if conf.GetConfig().SourceMode == "ldap" {
ldap := auth_connectors.New()
found, err := ldap.Authenticate(o.Ctx.Request.Context(), res.Username, res.Password)
fmt.Println("login", clientID, found, err)
if err != nil || !found {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
o.ServeJSON()
return
}
}
token, err := infrastructure.GetAuthConnector().Login(res.Username,
&http.Cookie{ // open a session
Name: "csrf_token",
Value: o.XSRFToken(),
})
if err != nil || token == nil {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
if !conf.GetConfig().Local {
token, err := infrastructure.GetAuthConnector().Login(
clientID, res.Username,
&http.Cookie{ // open a session
Name: "csrf_token",
Value: o.XSRFToken(),
})
fmt.Println("login token", token, err)
if err != nil || token == nil {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
} else {
o.Data["json"] = token
}
} else {
o.Data["json"] = token
t := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).Search(
nil, fmt.Sprintf("%v", model.SELF.EnumIndex()), false)
if t.Err == "" && len(t.Data) > 0 {
token := &auth_connectors.Token{
Username: res.Username,
Password: res.Password,
TokenType: "Bearer",
Active: true,
ExpiresIn: 3600,
AccessToken: "localtoken",
}
now := time.Now().UTC()
now = now.Add(time.Duration(token.ExpiresIn) * time.Second)
unix := now.Unix()
c := claims.GetClaims().AddClaimsToToken(clientID, res.Username, t.Data[0].(*model.Peer))
c.Session.AccessToken["exp"] = unix
b, _ := json.Marshal(c)
token.AccessToken = token.AccessToken + "." + base64.StdEncoding.EncodeToString(b)
o.Data["json"] = token
} else {
o.Data["json"] = t.Err
o.Ctx.ResponseWriter.WriteHeader(401)
}
}
o.ServeJSON()
}
@@ -79,18 +125,24 @@ func (o *OAuthController) LoginLDAP() {
// @Title Introspection
// @Description introspect token
// @Param body body models.Token true "The token info"
// @Param client_id query string true "the client_id you want to get"
// @Success 200 {string}
// @router /refresh [post]
func (o *OAuthController) Refresh() {
clientID := o.Ctx.Input.Query("client_id")
var token auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(100000), &token)
// refresh token
newToken, err := infrastructure.GetAuthConnector().Refresh(&token)
if err != nil || newToken == nil {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
if !conf.GetConfig().Local {
newToken, err := infrastructure.GetAuthConnector().Refresh(clientID, &token)
if err != nil || newToken == nil {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
} else {
o.Data["json"] = newToken
}
} else {
o.Data["json"] = newToken
o.Data["json"] = token
}
o.ServeJSON()
}
@@ -108,11 +160,12 @@ func (o *OAuthController) Introspect() {
} else {
reqToken = splitToken[1]
}
token, err := infrastructure.GetAuthConnector().Introspect(reqToken)
if err != nil || !token {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
if !conf.GetConfig().Local {
token, err := infrastructure.GetAuthConnector().Introspect(reqToken)
if err != nil || !token {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
}
}
o.ServeJSON()
}
@@ -149,7 +202,7 @@ func (o *OAuthController) InternalAuthForward() {
} else {
reqToken = splitToken[1]
}
origin, publicKey, external := o.extractOrigin()
origin, publicKey, external := o.extractOrigin(o.Ctx.Request)
if !infrastructure.GetAuthConnector().CheckAuthForward( //reqToken != "" &&
reqToken, publicKey, origin,
o.Ctx.Request.Header.Get("X-Forwarded-Method"),
@@ -161,7 +214,8 @@ func (o *OAuthController) InternalAuthForward() {
o.ServeJSON()
}
func (o *OAuthController) extractOrigin() (string, string, bool) {
func (o *OAuthController) extractOrigin(request *http.Request) (string, string, bool) {
user, peerID, groups := oclib.ExtractTokenInfo(*request)
external := true
publicKey := ""
origin := o.Ctx.Request.Header.Get("X-Forwarded-Host")
@@ -174,15 +228,15 @@ func (o *OAuthController) extractOrigin() (string, string, bool) {
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
pp := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).Search(nil, searchStr, false)
if pp.Code != 200 || len(pp.Data) == 0 { // TODO: add state of partnership
return "", "", external
}
p := peer.Data[0].(*model.Peer)
p := pp.Data[0].(*model.Peer)
publicKey = p.PublicKey
origin = p.Url
origin = p.APIUrl
if origin != "" { // is external
if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") || p.State == model.SELF {
if p.Relation == peer.SELF {
external = false
}
} else {
@@ -190,3 +244,29 @@ func (o *OAuthController) extractOrigin() (string, string, bool) {
}
return origin, publicKey, external
}
func ExtractClient(request http.Request) string {
reqToken := request.Header.Get("Authorization")
splitToken := strings.Split(reqToken, "Bearer ")
if len(splitToken) < 2 {
reqToken = ""
} else {
reqToken = splitToken[1]
}
if reqToken != "" {
token := strings.Split(reqToken, ".")
if len(token) > 2 {
bytes, err := base64.StdEncoding.DecodeString(token[2])
if err != nil {
return ""
}
m := map[string]interface{}{}
err = json.Unmarshal(bytes, &m)
if err != nil {
return ""
}
return m["session"].(map[string]interface{})["id_token"].(map[string]interface{})["client_id"].(string)
}
}
return ""
}

View File

@@ -16,7 +16,8 @@ type PermissionController struct {
// @Success 200 {permission} string
// @router / [get]
func (o *PermissionController) GetAll() {
role, err := infrastructure.GetPermissionConnector().GetPermission("", "")
clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetPermission("", "")
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -41,7 +42,8 @@ func (o *PermissionController) GetAll() {
// @router /role/:id [get]
func (o *PermissionController) GetByRole() {
id := o.Ctx.Input.Param(":id")
role, err := infrastructure.GetPermissionConnector().GetPermissionByRole(id)
clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetPermissionByRole(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -66,7 +68,8 @@ func (o *PermissionController) GetByRole() {
// @router /user/:id [get]
func (o *PermissionController) GetByUser() {
id := o.Ctx.Input.Param(":id")
role, err := infrastructure.GetPermissionConnector().GetPermissionByUser(id, true)
clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetPermissionByUser(id, true)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -92,7 +95,8 @@ func (o *PermissionController) GetByUser() {
func (o *PermissionController) Get() {
id := o.Ctx.Input.Param(":id")
rel := o.Ctx.Input.Param(":relation")
role, err := infrastructure.GetPermissionConnector().GetPermission(id, rel)
clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetPermission(id, rel)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -115,7 +119,8 @@ func (o *PermissionController) Get() {
// @Success 200 {string} delete success!
// @router /clear [delete]
func (o *PermissionController) Clear() {
role, code, err := infrastructure.GetPermissionConnector().DeletePermission("", "", true)
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).DeletePermission("", "", true)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -144,7 +149,8 @@ func (o *PermissionController) Bind() {
permission_id := o.Ctx.Input.Param(":permission_id")
role_id := o.Ctx.Input.Param(":role_id")
rel := o.Ctx.Input.Param(":relation")
role, code, err := infrastructure.GetPermissionConnector().BindPermission(role_id, permission_id, rel)
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).BindPermission(role_id, permission_id, rel)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -173,7 +179,8 @@ func (o *PermissionController) UnBind() {
permission_id := o.Ctx.Input.Param(":permission_id")
role_id := o.Ctx.Input.Param(":role_id")
rel := o.Ctx.Input.Param(":relation")
role, code, err := infrastructure.GetPermissionConnector().UnBindPermission(role_id, permission_id, rel)
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).UnBindPermission(role_id, permission_id, rel)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,

View File

@@ -19,7 +19,8 @@ type RoleController struct {
func (o *RoleController) Post() {
// store and return Id or post with UUID
id := o.Ctx.Input.Param(":id")
role, code, err := infrastructure.GetPermissionConnector().CreateRole(id)
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).CreateRole(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -44,7 +45,8 @@ func (o *RoleController) Post() {
// @router /user/:id [get]
func (o *RoleController) GetByUser() {
id := o.Ctx.Input.Param(":id")
role, err := infrastructure.GetPermissionConnector().GetRoleByUser(id)
clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetRoleByUser(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -67,7 +69,8 @@ func (o *RoleController) GetByUser() {
// @Success 200 {role} string
// @router / [get]
func (o *RoleController) GetAll() {
role, err := infrastructure.GetPermissionConnector().GetRole("")
clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetRole("")
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -92,7 +95,8 @@ func (o *RoleController) GetAll() {
// @router /:id [get]
func (o *RoleController) Get() {
id := o.Ctx.Input.Param(":id")
role, err := infrastructure.GetPermissionConnector().GetRole(id)
clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetRole(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -117,7 +121,8 @@ func (o *RoleController) Get() {
// @router /:id [delete]
func (o *RoleController) Delete() {
id := o.Ctx.Input.Param(":id")
role, code, err := infrastructure.GetPermissionConnector().DeleteRole(id)
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).DeleteRole(id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -140,7 +145,8 @@ func (o *RoleController) Delete() {
// @Success 200 {string} delete success!
// @router /clear [delete]
func (o *RoleController) Clear() {
role, code, err := infrastructure.GetPermissionConnector().DeleteRole("")
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).DeleteRole("")
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -167,7 +173,8 @@ func (o *RoleController) Clear() {
func (o *RoleController) Bind() {
user_id := o.Ctx.Input.Param(":user_id")
role_id := o.Ctx.Input.Param(":role_id")
role, code, err := infrastructure.GetPermissionConnector().BindRole(user_id, role_id)
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).BindRole(user_id, role_id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,
@@ -194,7 +201,8 @@ func (o *RoleController) Bind() {
func (o *RoleController) UnBind() {
user_id := o.Ctx.Input.Param(":user_id")
role_id := o.Ctx.Input.Param(":role_id")
role, code, err := infrastructure.GetPermissionConnector().UnBindRole(user_id, role_id)
clientID := ExtractClient(*o.Ctx.Request)
role, code, err := infrastructure.GetPermissionConnector(clientID).UnBindRole(user_id, role_id)
if err != nil {
o.Data["json"] = map[string]interface{}{
"data": nil,

View File

@@ -14,7 +14,10 @@ type VersionController struct {
// @Success 200
// @router / [get]
func (c *VersionController) GetAll() {
c.Data["json"] = map[string]string{"version": "1"}
c.Data["json"] = map[string]string{
"service": "oc-auth",
"version": "1",
}
c.ServeJSON()
}
@@ -23,6 +26,9 @@ func (c *VersionController) GetAll() {
// @Success 200
// @router /discovery [get]
func (c *VersionController) Get() {
c.Data["json"] = map[string]string{"version": "1"}
c.Data["json"] = map[string]string{
"service": "oc-auth",
"version": "1",
}
c.ServeJSON()
}

View File

@@ -1,22 +1,6 @@
version: '3.4'
services:
traefik:
image: traefik:v2.10.4
container_name: traefik
networks:
- catalog
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--log.level=DEBUG"
ports:
- "8080:80"
- "8082:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
oc-auth:
image: 'oc-auth:latest'
ports:
@@ -24,18 +8,25 @@ services:
container_name: oc-auth
labels:
- "traefik.enable=true"
- "traefik.http.routers.auth.entrypoints=web"
- "traefik.http.routers.auth.rule=PathPrefix(`/auth`)"
- "traefik.http.middlewares.auth-rewrite.replacepathregex.regex=^/auth(.*)"
- "traefik.http.middlewares.auth-rewrite.replacepathregex.replacement=/oc$$1"
- "traefik.http.routers.auth.middlewares=auth-rewrite"
- "traefik.http.services.auth.loadbalancer.server.port=8080"
- "traefik.http.middlewares.auth.forwardauth.address=http://oc-auth:8080/oc/forward"
- "traefik.http.routers.workflow.rule=PathPrefix(/auth)"
environment:
LDAP_ENDPOINTS: ldap:389
LDAP_BINDDN: cn=admin,dc=example,dc=com
LDAP_BINDPW: password
LDAP_BASEDN: "dc=example,dc=com"
LDAP_USER_BASEDN: "ou=users,dc=example,dc=com"
LDAP_ROLE_BASEDN: "ou=AppRoles,dc=example,dc=com"
networks:
- catalog
- oc
volumes:
- ./pem:/etc/oc/pem
- ./pem/private.pem:/keys/private/private.pem
- ./pem/public.pem:/keys/public/public.pem
networks:
catalog:
oc:
external: true

View File

@@ -2,9 +2,10 @@
"MONGO_URL":"mongodb://mongo:27017/",
"MONGO_DATABASE":"DC_myDC",
"NATS_URL": "nats://nats:4222",
"PORT" : 8080,
"AUTH_CONNECTOR_HOST": "hydra",
"PRIVATE_KEY_PATH": "/etc/oc/pem/private.pem",
"PUBLIC_KEY_PATH": "/etc/oc/pem/public.pem",
"LDAP_ENDPOINTS": "ldap:389"
"AUTH_CONNECTOR_PUBLIC_HOST": "hydra",
"PRIVATE_KEY_PATH": "/keys/private/private.pem",
"PUBLIC_KEY_PATH": "/keys/public/public.pem",
"LDAP_ENDPOINTS": "ldap:389",
"LOCAL": false
}

4
env.env Normal file
View File

@@ -0,0 +1,4 @@
KUBERNETES_SERVICE_HOST=192.168.47.20
KUBE_CA="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFTVlk3ZHZhNEdYTVdkMy9jMlhLN3JLYjlnWXgyNSthaEE0NmkyNVBkSFAKRktQL2UxSVMyWVF0dzNYZW1TTUQxaStZdzJSaVppNUQrSVZUamNtNHdhcnFvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWtlUVJpNFJiODduME5yRnZaWjZHClc2SU55NnN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnRXA5ck04WmdNclRZSHYxZjNzOW5DZXZZeWVVa3lZUk4KWjUzazdoaytJS1FDSVFDbk05TnVGKzlTakIzNDFacGZ5ays2NEpWdkpSM3BhcmVaejdMd2lhNm9kdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
KUBE_CERT="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJWUxWNkFPQkdrU1F3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOekl6TVRFeU1ETTJNQjRYRFRJME1EZ3dPREV3TVRNMU5sb1hEVEkxTURndwpPREV3TVRNMU5sb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJGQ2Q1MFdPeWdlQ2syQzcKV2FrOWY4MVAvSkJieVRIajRWOXBsTEo0ck5HeHFtSjJOb2xROFYxdUx5RjBtOTQ2Nkc0RmRDQ2dqaXFVSk92Swp3NVRPNnd5alNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCVFJkOFI5cXVWK2pjeUVmL0ovT1hQSzMyS09XekFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlFQTArbThqTDBJVldvUTZ0dnB4cFo4NVlMalF1SmpwdXM0aDdnSXRxS3NmUVVDSUI2M2ZNdzFBMm5OVWU1TgpIUGZOcEQwSEtwcVN0Wnk4djIyVzliYlJUNklZCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTWpNeE1USXdNell3SGhjTk1qUXdPREE0TVRBeE16VTJXaGNOTXpRd09EQTJNVEF4TXpVMgpXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTWpNeE1USXdNell3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFRc3hXWk9pbnIrcVp4TmFEQjVGMGsvTDF5cE01VHAxOFRaeU92ektJazQKRTFsZWVqUm9STW0zNmhPeVljbnN3d3JoNnhSUnBpMW5RdGhyMzg0S0Z6MlBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBYZkVmYXJsZm8zTWhIL3lmemx6Cnl0OWlqbHN3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUxJL2dNYnNMT3MvUUpJa3U2WHVpRVMwTEE2cEJHMXgKcnBlTnpGdlZOekZsQWlFQW1wdjBubjZqN3M0MVI0QzFNMEpSL0djNE53MHdldlFmZWdEVGF1R2p3cFk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
KUBE_DATA="LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5ZS1BFb1dhd1NKUzJlRW5oWmlYMk5VZlY1ZlhKV2krSVNnV09TNFE5VTlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVUozblJZN0tCNEtUWUx0WnFUMS96VS84a0Z2Sk1lUGhYMm1Vc25pczBiR3FZblkyaVZEeApYVzR2SVhTYjNqcm9iZ1YwSUtDT0twUWs2OHJEbE03ckRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="

23
go.mod
View File

@@ -1,22 +1,27 @@
module oc-auth
go 1.22.0
go 1.24.6
require (
cloud.o-forge.io/core/oc-lib v0.0.0-20241216081754-21d08204b5ba
cloud.o-forge.io/core/oc-lib v0.0.0-20260210081202-3bcf0da56aa1
github.com/beego/beego/v2 v2.3.1
github.com/smartystreets/goconvey v1.7.2
go.uber.org/zap v1.27.0
)
replace cloud.o-forge.io/core/oc-lib => ../oc-lib
//replace cloud.o-forge.io/core/oc-lib => ../oc-lib
require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/biter777/countries v1.7.5 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/gofrs/uuid v4.3.0+incompatible // indirect
github.com/libp2p/go-libp2p/core v0.43.0-rc2 // indirect
github.com/nats-io/nats.go v1.37.0 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
go.uber.org/multierr v1.10.0 // indirect
)
@@ -57,11 +62,11 @@ require (
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.mongodb.org/mongo-driver v1.17.1 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

39
go.sum
View File

@@ -1,5 +1,7 @@
cloud.o-forge.io/core/oc-lib v0.0.0-20241216081754-21d08204b5ba h1:krqNxKaYJBBzitEy/LDTZwmbwGh+mxEksfo/rghYQd4=
cloud.o-forge.io/core/oc-lib v0.0.0-20241216081754-21d08204b5ba/go.mod h1:ya7Q+zHhaKM+XF6sAJ+avqHEVzaMnFJQih2X3TlTlGo=
cloud.o-forge.io/core/oc-lib v0.0.0-20260204083845-d9f646aac28b h1:/TkmuO5ERpHJCqNpKBlmzw8pYTVDGcFcDo+e1ndXlm0=
cloud.o-forge.io/core/oc-lib v0.0.0-20260204083845-d9f646aac28b/go.mod h1:T0UCxRd8w+qCVVC0NEyDiWIGC5ADwEbQ7hFcvftd4Ks=
cloud.o-forge.io/core/oc-lib v0.0.0-20260210081202-3bcf0da56aa1 h1:CSPqJlSepu0efDRFV8tv62Fg5XP2UwSZKfaaL81YuVY=
cloud.o-forge.io/core/oc-lib v0.0.0-20260210081202-3bcf0da56aa1/go.mod h1:jmyBwmsac/4V7XPL347qawF60JsBCDmNAMfn/ySXKYo=
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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -9,6 +11,8 @@ github.com/beego/beego/v2 v2.3.1 h1:7MUKMpJYzOXtCUsTEoXOxsDV/UcHw6CPbaWMlthVNsc=
github.com/beego/beego/v2 v2.3.1/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVDxd5ce4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/biter777/countries v1.7.5 h1:MJ+n3+rSxWQdqVJU8eBy9RqcdH6ePPn4PJHocVWUa+Q=
github.com/biter777/countries v1.7.5/go.mod h1:1HSpZ526mYqKJcpT5Ti1kcGQ0L0SrXWIaptUWjFfv2E=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -18,8 +22,11 @@ github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/etcd-io/etcd v3.3.17+incompatible/go.mod h1:cdZ77EstHBwVtD6iTgzgvogwcjo9m4iOqoijouPJ4bs=
@@ -88,6 +95,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/libp2p/go-libp2p/core v0.43.0-rc2 h1:1X1aDJNWhMfodJ/ynbaGLkgnC8f+hfBIqQDrzxFZOqI=
github.com/libp2p/go-libp2p/core v0.43.0-rc2/go.mod h1:NYeJ9lvyBv9nbDk2IuGb8gFKEOkIv/W5YRIy1pAJB2Q=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@@ -116,8 +125,9 @@ github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFP
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
@@ -126,10 +136,9 @@ github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPA
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
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/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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
@@ -150,8 +159,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
@@ -180,6 +189,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -200,6 +211,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -216,6 +229,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -231,6 +246,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -239,6 +256,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@@ -3,16 +3,17 @@ package auth_connectors
import (
"net/http"
"oc-auth/conf"
"strings"
"cloud.o-forge.io/core/oc-lib/tools"
)
type AuthConnector interface {
Status() tools.State
Login(username string, cookies ...*http.Cookie) (*Token, error)
Logout(token string, cookies ...*http.Cookie) (*Token, error)
Login(clientID string, username string, cookies ...*http.Cookie) (*Token, error)
Logout(clientID string, token string, cookies ...*http.Cookie) (*Token, error)
Introspect(token string, cookie ...*http.Cookie) (bool, error)
Refresh(token *Token) (*Token, error)
Refresh(client_id string, token *Token) (*Token, error)
CheckAuthForward(reqToken string, publicKey string, host string, method string, forward string, external bool) bool
}
@@ -37,5 +38,10 @@ var a = map[string]AuthConnector{
}
func GetAuthConnector() AuthConnector {
return a[conf.GetConfig().Auth]
for k := range a {
if strings.Contains(conf.GetConfig().Auth, k) {
return a[k]
}
}
return nil
}

View File

@@ -23,7 +23,6 @@ import (
type HydraConnector struct {
State string `json:"state"`
Scopes string `json:"scope"`
ClientID string `json:"client_id"`
ResponseType string `json:"response_type"`
Caller *tools.HTTPCaller
@@ -32,7 +31,10 @@ type HydraConnector struct {
func (a HydraConnector) Status() tools.State {
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
var responseBody map[string]interface{}
host := conf.GetConfig().AuthConnectorHost
host := conf.GetConfig().AuthConnectPublicHost
if conf.GetConfig().Local {
host = "localhost"
}
port := fmt.Sprintf("%v", conf.GetConfig().AuthConnectorPort)
resp, err := caller.CallGet("http://"+host+":"+port, "/health/ready")
if err != nil {
@@ -69,6 +71,7 @@ func (a HydraConnector) challenge(username string, url string, challenge string,
resp, err := a.Caller.CallRaw(http.MethodPut,
a.getPath(true, true), "/auth/requests/"+challenge+"/accept?"+challenge+"_challenge="+s[1],
body, "application/json", true, cookies...) // "remember": true, "subject": username
fmt.Println(a.getPath(true, true), "/auth/requests/"+challenge+"/accept?"+challenge+"_challenge="+s[1], resp, err)
if err != nil {
return nil, s[1], cookies, err
}
@@ -77,6 +80,7 @@ func (a HydraConnector) challenge(username string, url string, challenge string,
if err != nil {
return nil, s[1], cookies, err
}
fmt.Println(string(b))
var token Redirect
err = json.Unmarshal(b, &token)
if err != nil {
@@ -85,7 +89,7 @@ func (a HydraConnector) challenge(username string, url string, challenge string,
return &token, s[1], cookies, nil
}
func (a HydraConnector) Refresh(token *Token) (*Token, error) {
func (a HydraConnector) Refresh(client_id string, token *Token) (*Token, error) {
access := strings.Split(token.AccessToken, ".")
if len(access) > 2 {
token.AccessToken = strings.Join(access[0:2], ".")
@@ -94,11 +98,11 @@ func (a HydraConnector) Refresh(token *Token) (*Token, error) {
if err != nil || !isValid {
return nil, err
}
_, err = a.Logout(token.AccessToken)
_, err = a.Logout(client_id, token.AccessToken)
if err != nil {
return nil, err
}
return a.Login(token.Username)
return a.Login(client_id, token.Username)
}
func (a HydraConnector) tryLog(username string, url string, subpath string, challenge string, cookies ...*http.Cookie) (*Redirect, string, []*http.Cookie, error) {
@@ -120,9 +124,10 @@ func (a HydraConnector) tryLog(username string, url string, subpath string, chal
return a.challenge(username, resp.Request.URL.String(), challenge, cookies...)
}
func (a HydraConnector) getClient() string {
func (a HydraConnector) getClient(clientID string) string {
resp, err := a.Caller.CallGet(a.getPath(true, false), "/clients")
if err != nil {
fmt.Println(err)
return ""
}
var clients []interface{}
@@ -130,15 +135,26 @@ func (a HydraConnector) getClient() string {
if err != nil || len(clients) == 0 {
return ""
}
for _, c := range clients {
if c.(map[string]interface{})["client_name"].(string) == clientID {
return c.(map[string]interface{})["client_id"].(string)
}
}
return clients[0].(map[string]interface{})["client_id"].(string)
}
func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Token, err error) {
clientID := a.getClient()
func (a HydraConnector) Login(clientID string, username string, cookies ...*http.Cookie) (t *Token, err error) {
clientID = a.getClient(clientID)
if clientID == "" {
return nil, errors.New("no client found")
}
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 {
if redirect == nil {
return nil, errors.New("no oauth redirection " + clientID)
}
return nil, err
}
redirect, _, cookies, err = a.tryLog(username, a.urlFormat(redirect.RedirectTo, a.getPath(false, true)), "", "consent", cookies...)
@@ -168,23 +184,26 @@ func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Toke
var m map[string]interface{}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
fmt.Println("login", b, err, a.getPath(false, true), "/token")
if err != nil {
return nil, err
}
err = json.Unmarshal(b, &token)
fmt.Println("login2", token, err)
if err != nil {
return nil, err
}
json.Unmarshal(b, &m)
pp := oclib.Search(nil, strconv.Itoa(peer.SELF.EnumIndex()), oclib.LibDataEnum(oclib.PEER))
pp := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).Search(nil, strconv.Itoa(peer.SELF.EnumIndex()), false)
if len(pp.Data) == 0 || pp.Code >= 300 || pp.Err != "" {
fmt.Println(pp.Data, pp.Code, pp.Err, strconv.Itoa(peer.SELF.EnumIndex()))
return nil, errors.New("peer not found")
}
now := time.Now().UTC()
now = now.Add(time.Duration(token.ExpiresIn) * time.Second)
unix := now.Unix()
c := claims.GetClaims().AddClaimsToToken(username, pp.Data[0].(*peer.Peer))
c := claims.GetClaims().AddClaimsToToken(clientID, username, pp.Data[0].(*peer.Peer))
c.Session.AccessToken["exp"] = unix
b, _ = json.Marshal(c)
@@ -194,7 +213,8 @@ func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Toke
return token, nil
}
func (a HydraConnector) Logout(token string, cookies ...*http.Cookie) (*Token, error) {
func (a HydraConnector) Logout(clientID string, token string, cookies ...*http.Cookie) (*Token, error) {
clientID = a.getClient(clientID)
access := strings.Split(token, ".")
if len(access) > 2 {
token = strings.Join(access[0:2], ".")
@@ -202,7 +222,7 @@ func (a HydraConnector) Logout(token string, cookies ...*http.Cookie) (*Token, e
p := a.getPath(false, true) + "/revoke"
urls := url.Values{}
urls.Add("token", token)
urls.Add("client_id", a.getClient())
urls.Add("client_id", clientID)
urls.Add("client_secret", conf.GetConfig().ClientSecret)
_, err := a.Caller.CallForm(http.MethodPost, p, "", urls, "application/x-www-form-urlencoded", true)
if err != nil {
@@ -234,6 +254,7 @@ func (a HydraConnector) Introspect(token string, cookie ...*http.Cookie) (bool,
}
var introspect Token
err = json.Unmarshal(b, &introspect)
fmt.Println(introspect.Active, token)
if err != nil {
return false, err
}
@@ -242,10 +263,16 @@ func (a HydraConnector) Introspect(token string, cookie ...*http.Cookie) (bool,
}
func (a HydraConnector) getPath(isAdmin bool, isOauth bool) string {
host := conf.GetConfig().AuthConnectorHost
host := conf.GetConfig().AuthConnectPublicHost
if isAdmin {
host = conf.GetConfig().AuthConnectorHost
}
if conf.GetConfig().Local {
host = "localhost"
}
port := fmt.Sprintf("%v", conf.GetConfig().AuthConnectorPort)
if isAdmin {
port = fmt.Sprintf("%v", conf.GetConfig().AuthConnectorAdminPort) + "/admin"
port = fmt.Sprintf("%v", conf.GetConfig().AuthConnectorAdminPort)
}
oauth := ""
if isOauth {

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"net"
"oc-auth/conf"
"strings"
@@ -31,8 +32,9 @@ var (
type conn interface {
Bind(bindDN, password string) error
SearchUser(user string, attrs ...string) ([]map[string]interface{}, error)
SearchUserRoles(user string, attrs ...string) ([]map[string]interface{}, error)
SearchRoles(attrs ...string) ([]map[string][]string, error)
SearchUser(user string, attrs ...string) ([]map[string][]string, error)
SearchUserRoles(user string, attrs ...string) ([]map[string][]string, error)
Close() error
}
@@ -47,6 +49,7 @@ type Config struct {
BindPass string `envconfig:"bindpw" json:"-" desc:"a LDAP bind password"`
BaseDN string `envconfig:"basedn" required:"true" desc:"a LDAP base DN for searching users"`
AttrClaims map[string]string `envconfig:"attr_claims" default:"name:name,sn:family_name,givenName:given_name,mail:email" desc:"a mapping of LDAP attributes to OpenID connect claims"`
UserBaseDN string `envconfig:"user_basedn" required:"true" desc:"a LDAP base DN for searching users"`
RoleBaseDN string `envconfig:"role_basedn" required:"true" desc:"a LDAP base DN for searching roles"`
RoleAttr string `envconfig:"role_attr" default:"description" desc:"a LDAP group's attribute that contains a role's name"`
RoleClaim string `envconfig:"role_claim" default:"https://github.com/i-core/werther/claims/roles" desc:"a name of an OpenID Connect claim that contains user roles"`
@@ -63,11 +66,12 @@ func New() *Client {
BindDN: conf.GetConfig().LDAPBindDN,
BindPass: conf.GetConfig().LDAPBindPW,
BaseDN: conf.GetConfig().LDAPBaseDN,
UserBaseDN: conf.GetConfig().LDAPUserBaseDN,
RoleBaseDN: conf.GetConfig().LDAPRoleBaseDN,
}
return &Client{
Config: cnf,
connector: &ldapConnector{BaseDN: cnf.BaseDN, RoleBaseDN: cnf.RoleBaseDN, IsTLS: cnf.IsTLS},
connector: &ldapConnector{BaseDN: cnf.BaseDN, RoleBaseDN: cnf.RoleBaseDN, UserBaseDN: cnf.UserBaseDN, IsTLS: cnf.IsTLS},
cache: freecache.NewCache(cnf.CacheSize * 1024),
}
}
@@ -78,31 +82,31 @@ type Client struct {
cache *freecache.Cache
}
func (cli *Client) Authenticate(ctx context.Context, username, password string) (bool, error) {
func (cli *Client) Authenticate(ctx context.Context, username string, password string) (bool, error) {
if username == "" || password == "" {
return false, nil
}
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
fmt.Println("Connect", ctx, username, password)
cn, ok := <-cli.connect(ctx)
cancel()
if !ok {
return false, errConnectionTimeout
}
defer cn.Close()
fmt.Println("findBasicUserDetails", cn, username, password)
// Find a user DN by his or her username.
details, err := cli.findBasicUserDetails(cn, username, []string{"dn"})
if err != nil {
if err != nil || details == nil {
return false, err
}
if details == nil {
return false, nil
}
if err := cn.Bind(details["dn"].(string), password); err != nil {
fmt.Println(details)
a := details["dn"]
fmt.Println(a)
log.Println("Binding DN:", a[0], "with password:", password)
if err := cn.Bind(a[0], password); err != nil {
fmt.Println(err)
if err == errInvalidCredentials {
return false, nil
}
@@ -118,6 +122,21 @@ func (cli *Client) Authenticate(ctx context.Context, username, password string)
return true, nil
}
func (cli *Client) GetRoles(ctx context.Context) (map[string]LDAPRoles, error) {
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
cn, ok := <-cli.connect(ctx)
cancel()
if !ok {
return map[string]LDAPRoles{}, errConnectionTimeout
}
defer cn.Close()
// Find a user DN by his or her username.
return cli.findRoles(cn, "dn", "member", "uniqueMember")
}
// Claim is the FindOIDCClaims result struct
type LDAPClaim struct {
Code string // the root claim name
@@ -125,6 +144,10 @@ type LDAPClaim struct {
Value interface{} // the value
}
type LDAPRoles struct {
Members map[string][]string
}
// FindOIDCClaims finds all OIDC claims for a user.
func (cli *Client) FindOIDCClaims(ctx context.Context, username string) ([]LDAPClaim, error) {
if username == "" {
@@ -193,11 +216,12 @@ func (cli *Client) FindOIDCClaims(ctx context.Context, username string) ([]LDAPC
roles := make(map[string]interface{})
for _, entry := range entries {
roleDN, ok := entry["dn"].(string)
if !ok || roleDN == "" {
roleDNs, ok := entry["dn"]
if !ok || len(roleDNs) == 0 {
log.Infow("No required LDAP attribute for a role", "ldapAttribute", "dn", "entry", entry)
continue
}
roleDN := roleDNs[0]
if entry[cli.RoleAttr] == nil {
log.Infow("No required LDAP attribute for a role", "ldapAttribute", cli.RoleAttr, "roleDN", roleDN)
continue
@@ -207,7 +231,7 @@ func (cli *Client) FindOIDCClaims(ctx context.Context, username string) ([]LDAPC
// It's sufficient to compare the DN's suffix with the base DN.
n, k := len(roleDN), len(cli.RoleBaseDN)
if n < k || !strings.EqualFold(roleDN[n-k:], cli.RoleBaseDN) {
panic("You should never see that")
return nil, errors.New("You should never see that")
}
// The DN without the role's base DN must contain a CN and OU
// where the CN is for uniqueness only, and the OU is an application id.
@@ -259,7 +283,7 @@ func (cli *Client) connect(ctx context.Context) <-chan conn {
cn, err := cli.connector.Connect(ctx, addr)
if err != nil {
fmt.Println("Failed to create a LDAP connection", "address", addr)
fmt.Println("Failed to create a LDAP connection", "address", addr, err)
return
}
select {
@@ -278,27 +302,100 @@ func (cli *Client) connect(ctx context.Context) <-chan conn {
return ch
}
func (cli *Client) findRoles(cn conn, attrs ...string) (map[string]LDAPRoles, error) {
fmt.Println("cli", cli.BindDN, cli.BindPass)
if cli.BindDN != "" {
// We need to login to a LDAP server with a service account for retrieving user data.
if err := cn.Bind(cli.BindDN, cli.BindPass); err != nil {
return map[string]LDAPRoles{}, errors.New(err.Error() + " : failed to login to a LDAP woth a service account")
}
}
entries, err := cn.SearchRoles(attrs...)
fmt.Println("entries", entries)
if err != nil {
return map[string]LDAPRoles{}, err
}
claims := map[string]LDAPRoles{}
for _, entry := range entries {
roleDNs, ok := entry["dn"]
if !ok || len(roleDNs) == 0 {
continue
}
roleDN := roleDNs[0]
// Ensure that a role's DN is inside of the role's base DN.
// It's sufficient to compare the DN's suffix with the base DN.
n, k := len(roleDN), len(cli.RoleBaseDN)
if n < k || !strings.EqualFold(roleDN[n-k:], cli.RoleBaseDN) {
return nil, errors.New("You should never see that")
}
// The DN without the role's base DN must contain a CN and OU
// where the CN is for uniqueness only, and the OU is an application id.
path := strings.Split(roleDN[:n-k-1], ",")
if len(path) != 2 {
continue
}
appID := path[1][len("OU="):]
if _, ok := claims[appID]; !ok {
claims[appID] = LDAPRoles{
Members: map[string][]string{},
}
}
role := path[0][len("cn="):]
if claims[appID].Members[role] == nil {
claims[appID].Members[role] = []string{}
}
fmt.Println("entry", entry)
memberDNs, ok := entry["member"]
for _, memberDN := range memberDNs {
if !ok || memberDN == "" {
continue
}
path = strings.Split(memberDN[:n-k-1], ",")
if len(path) < 1 {
continue
}
member := strings.Split(path[0][len("uid="):], ",")
claims[appID].Members[role] = append(claims[appID].Members[role], member[0])
}
memberDNs, ok = entry["uniqueMember"]
for _, memberDN := range memberDNs {
if !ok || memberDN == "" {
continue
}
path = strings.Split(memberDN[:n-k-1], ",")
if len(path) < 1 {
continue
}
member := strings.Split(path[0][len("uid="):], ",")
claims[appID].Members[role] = append(claims[appID].Members[role], member[0])
}
}
return claims, nil
}
// findBasicUserDetails finds user's LDAP attributes that were specified. It returns nil if no such user.
func (cli *Client) findBasicUserDetails(cn conn, username string, attrs []string) (map[string]interface{}, error) {
func (cli *Client) findBasicUserDetails(cn conn, username string, attrs []string) (map[string][]string, error) {
fmt.Println("Second woth : ", cli.BindDN, cli.BindPass)
if cli.BindDN != "" {
// We need to login to a LDAP server with a service account for retrieving user data.
if err := cn.Bind(cli.BindDN, cli.BindPass); err != nil {
return nil, errors.New(err.Error() + " : failed to login to a LDAP woth a service account")
}
}
entries, err := cn.SearchUser(username, attrs...)
if err != nil {
return nil, err
}
if len(entries) != 1 {
if len(entries) == 0 {
// We didn't find the user.
fmt.Println("user not found")
return nil, nil
}
var (
entry = entries[0]
details = make(map[string]interface{})
details = make(map[string][]string)
)
for _, attr := range attrs {
if v, ok := entry[attr]; ok {
@@ -311,6 +408,7 @@ func (cli *Client) findBasicUserDetails(cn conn, username string, attrs []string
type ldapConnector struct {
BaseDN string
RoleBaseDN string
UserBaseDN string
IsTLS bool
}
@@ -332,12 +430,13 @@ func (c *ldapConnector) Connect(ctx context.Context, addr string) (conn, error)
ldapcn := ldap.NewConn(tcpcn, c.IsTLS)
ldapcn.Start()
return &ldapConn{Conn: ldapcn, BaseDN: c.BaseDN, RoleBaseDN: c.RoleBaseDN}, nil
return &ldapConn{Conn: ldapcn, BaseDN: c.BaseDN, UserBaseDN: c.UserBaseDN, RoleBaseDN: c.RoleBaseDN}, nil
}
type ldapConn struct {
*ldap.Conn
BaseDN string
UserBaseDN string
RoleBaseDN string
}
@@ -349,35 +448,42 @@ func (c *ldapConn) Bind(bindDN, password string) error {
return err
}
func (c *ldapConn) SearchUser(user string, attrs ...string) ([]map[string]interface{}, error) {
func (c *ldapConn) SearchUser(user string, attrs ...string) ([]map[string][]string, error) {
query := fmt.Sprintf(
"(&(|(objectClass=organizationalPerson)(objectClass=inetOrgPerson))"+
"(|(uid=%[1]s)(mail=%[1]s)(userPrincipalName=%[1]s)(sAMAccountName=%[1]s)))", user)
return c.searchEntries(c.BaseDN, query, attrs)
return c.searchEntries(c.UserBaseDN, query, attrs)
}
func (c *ldapConn) SearchUserRoles(user string, attrs ...string) ([]map[string]interface{}, error) {
func (c *ldapConn) SearchUserRoles(user string, attrs ...string) ([]map[string][]string, error) {
query := fmt.Sprintf("(|"+
"(&(|(objectClass=group)(objectClass=groupOfNames))(member=%[1]s))"+
"(&(|(objectClass=group)(objectClass=groupOfNames)(objectClass=groupofnames))(member=%[1]s))"+
"(&(objectClass=groupOfUniqueNames)(uniqueMember=%[1]s))"+
")", user)
return c.searchEntries(c.RoleBaseDN, query, attrs)
}
func (c *ldapConn) SearchRoles(attrs ...string) ([]map[string][]string, error) {
query := "(|(&(|(objectClass=group)(objectClass=groupOfNames)(objectClass=groupofnames))))"
return c.searchEntries(c.RoleBaseDN, query, attrs)
}
// searchEntries executes a LDAP query, and returns a result as entries where each entry is mapping of LDAP attributes.
func (c *ldapConn) searchEntries(baseDN, query string, attrs []string) ([]map[string]interface{}, error) {
func (c *ldapConn) searchEntries(baseDN, query string, attrs []string) ([]map[string][]string, error) {
fmt.Println(baseDN, query, attrs)
req := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, query, attrs, nil)
res, err := c.Search(req)
if err != nil {
return nil, err
}
fmt.Println(res.Entries)
var entries []map[string]interface{}
var entries []map[string][]string
for _, v := range res.Entries {
entry := map[string]interface{}{"dn": v.DN}
entry := map[string][]string{"dn": {v.DN}}
for _, attr := range v.Attributes {
// We need the first value only for the named attribute.
entry[attr.Name] = attr.Values[0]
entry[attr.Name] = attr.Values
}
entries = append(entries, entry)
}

View File

@@ -2,13 +2,14 @@ package claims
import (
"oc-auth/conf"
"strings"
"cloud.o-forge.io/core/oc-lib/models/peer"
)
// Tokenizer interface
type ClaimService interface {
AddClaimsToToken(userId string, peer *peer.Peer) Claims
AddClaimsToToken(clientID string, userId string, peer *peer.Peer) Claims
DecodeClaimsInToken(host string, method string, forward string, sessionClaims Claims, publicKey string, external bool) (bool, error)
}
@@ -28,5 +29,10 @@ var t = map[string]ClaimService{
}
func GetClaims() ClaimService {
return t[conf.GetConfig().Auth]
for k := range t {
if strings.Contains(conf.GetConfig().Auth, k) {
return t[k]
}
}
return nil
}

View File

@@ -4,6 +4,7 @@ import (
"crypto/sha256"
"encoding/pem"
"errors"
"fmt"
"oc-auth/conf"
"oc-auth/infrastructure/perms_connectors"
"oc-auth/infrastructure/utils"
@@ -119,21 +120,23 @@ func (h HydraClaims) DecodeClaimsInToken(host string, method string, forward str
Relation: "permits" + strings.ToUpper(meth.String()),
Object: p.(string),
}
return perms_connectors.GetPermissionConnector().CheckPermission(perm, nil, true), nil
return perms_connectors.GetPermissionConnector("").CheckPermission(perm, nil, true), nil
}
}
return false, errors.New("no permission found")
}
// add claims to token method of HydraTokenizer
func (h HydraClaims) AddClaimsToToken(userId string, p *peer.Peer) Claims {
func (h HydraClaims) AddClaimsToToken(clientID string, userId string, p *peer.Peer) Claims {
claims := Claims{}
perms, err := perms_connectors.KetoConnector{}.GetPermissionByUser(userId, true)
if err != nil {
return claims
}
claims.Session.AccessToken = make(map[string]interface{})
claims.Session.IDToken = make(map[string]interface{})
fmt.Println("PERMS err 1", perms, err)
for _, perm := range perms {
key, err := h.generateKey(strings.ReplaceAll(perm.Relation, "permits", ""), perm.Subject)
if err != nil {
@@ -141,19 +144,19 @@ func (h HydraClaims) AddClaimsToToken(userId string, p *peer.Peer) Claims {
}
claims.Session.AccessToken[key] = perm.Subject
}
sign, err := h.encodeSignature(p.Url)
sign, err := h.encodeSignature(p.APIUrl)
if err != nil {
return claims
}
claims.Session.IDToken["username"] = userId
claims.Session.IDToken["peer_id"] = p.UUID
// we should get group from user
groups, err := perms_connectors.KetoConnector{}.GetGroupByUser(userId)
if err != nil {
return claims
}
claims.Session.IDToken["client_id"] = clientID
claims.Session.IDToken["groups"] = groups
claims.Session.IDToken["signature"] = sign
return claims
}
// add signature in the token MISSING

View File

@@ -10,8 +10,8 @@ func GetAuthConnector() auth_connectors.AuthConnector {
return auth_connectors.GetAuthConnector()
}
func GetPermissionConnector() perms_connectors.PermConnector {
return perms_connectors.GetPermissionConnector()
func GetPermissionConnector(client string) perms_connectors.PermConnector {
return perms_connectors.GetPermissionConnector(client)
}
func GetClaims() claims.ClaimService {

View File

@@ -6,24 +6,29 @@ import (
"fmt"
"oc-auth/conf"
"oc-auth/infrastructure/utils"
"strings"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/tools"
)
type KetoConnector struct{}
type KetoConnector struct {
Client string
}
func (k KetoConnector) SetClient(client string) {
k.Client = client
}
func (k KetoConnector) namespace() string {
return "open-cloud"
}
func (k KetoConnector) scope() string {
return "oc-auth"
return "oc-auth-realm"
}
func (f KetoConnector) permToQuery(perm Permission, permDependancies *Permission) string {
n := "?namespace=" + perm.Namespace()
n := "?namespace=" + f.namespace()
if perm.Object != "" {
n += "&object=" + perm.Object
}
@@ -51,7 +56,10 @@ func (f KetoConnector) permToQuery(perm Permission, permDependancies *Permission
func (k KetoConnector) Status() tools.State {
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
var responseBody map[string]interface{}
host := conf.GetConfig().PermissionConnectorHost
host := conf.GetConfig().PermissionConnectorReadHost
if conf.GetConfig().Local {
host = "localhost"
}
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorPort)
resp, err := caller.CallGet("http://"+host+":"+port, "/health/ready")
if err != nil {
@@ -73,7 +81,7 @@ func (k KetoConnector) CheckPermission(perm Permission, permDependancies *Permis
perms, err := k.GetPermission(perm.Object, perm.Relation)
if err != nil {
log := oclib.GetLogger()
log.Error().Msg(err.Error())
log.Error().Msg("CheckPermission " + err.Error())
return false
}
return len(perms) > 0
@@ -189,6 +197,7 @@ func (k KetoConnector) GetPermissionByRole(roleID string) ([]Permission, error)
}
func (k KetoConnector) GetPermissionByUser(userID string, internal bool) ([]Permission, error) {
roles, err := k.get("", "member", userID)
fmt.Println("ROLES", roles, err)
if err != nil {
return nil, err
}
@@ -211,7 +220,10 @@ func (k KetoConnector) GetPermissionByUser(userID string, internal bool) ([]Perm
func (k KetoConnector) get(object string, relation string, subject string) ([]Permission, error) {
t := []Permission{}
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
host := conf.GetConfig().PermissionConnectorHost
host := conf.GetConfig().PermissionConnectorReadHost
if conf.GetConfig().Local {
host = "localhost"
}
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorPort)
resp, err := caller.CallGet("http://"+host+":"+port, "/relation-tuples"+k.permToQuery(
Permission{Object: object, Relation: relation, Subject: subject}, nil))
@@ -235,7 +247,7 @@ func (k KetoConnector) get(object string, relation string, subject string) ([]Pe
return t, nil
}
func (k KetoConnector) binds(subject string, relation string, object string) (string, int, error) {
func (k KetoConnector) binds(object string, relation string, subject string) (string, int, error) {
_, code, err := k.createRelationShip(object, relation, subject, nil)
if err != nil {
return object, code, err
@@ -244,6 +256,7 @@ func (k KetoConnector) binds(subject string, relation string, object string) (st
}
func (k KetoConnector) BindRole(userID string, roleID string) (string, int, error) {
fmt.Println("BIND ROLE", userID, roleID)
return k.binds(userID, "member", roleID)
}
@@ -324,9 +337,6 @@ func (k KetoConnector) UnBindPermission(roleID string, permID string, relation s
}
func (k KetoConnector) createRelationShip(object string, relation string, subject string, subPerm *Permission) (*Permission, int, error) {
exist, err := k.get(object, relation, subject)
if strings.Contains(subject, "/workflow/:id") {
fmt.Println("subject", subject, relation, exist, err)
}
if err == nil && len(exist) > 0 {
return nil, 409, errors.New("Relation already exist")
}
@@ -338,21 +348,25 @@ func (k KetoConnector) createRelationShip(object string, relation string, subjec
if err != nil {
return nil, code, err
}
body["subject_set"] = map[string]interface{}{"namespace": s.Namespace(), "object": s.Object, "relation": s.Relation, "subject_id": s.Subject}
body["subject_set"] = map[string]interface{}{"namespace": k.namespace(), "object": s.Object, "relation": s.Relation, "subject_id": s.Subject}
}
host := conf.GetConfig().PermissionConnectorWriteHost
if conf.GetConfig().Local {
host = "localhost"
}
host := conf.GetConfig().PermissionConnectorHost
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorAdminPort)
b, err := caller.CallPut("http://"+host+":"+port, "/relation-tuples", body)
if err != nil {
log := oclib.GetLogger()
log.Error().Msg(err.Error())
log.Error().Msg("createRelationShip" + err.Error())
return nil, 500, err
}
var data map[string]interface{}
err = json.Unmarshal(b, &data)
if err != nil {
fmt.Println(string(b), err)
log := oclib.GetLogger()
log.Error().Msg(err.Error())
log.Error().Msg("createRelationShip2" + err.Error())
return nil, 500, err
}
perm := &Permission{
@@ -378,12 +392,15 @@ func (k KetoConnector) deleteRelationShip(object string, relation string, subjec
}
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
n := k.permToQuery(Permission{Object: object, Relation: relation, Subject: subject}, subPerm)
host := conf.GetConfig().PermissionConnectorHost
host := conf.GetConfig().PermissionConnectorWriteHost
if conf.GetConfig().Local {
host = "localhost"
}
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorAdminPort)
b, err := caller.CallDelete("http://"+host+":"+port, "/relation-tuples"+n)
if err != nil {
log := oclib.GetLogger()
log.Error().Msg(err.Error())
log.Error().Msg("deleteRelationShip " + err.Error())
return nil, 500, err
}
var data map[string]interface{}

View File

@@ -1,6 +1,9 @@
package perms_connectors
import (
"oc-auth/conf"
"strings"
"cloud.o-forge.io/core/oc-lib/tools"
)
@@ -21,6 +24,7 @@ func (k Permission) Scope() string {
type PermConnector interface {
Status() tools.State
SetClient(scope string)
CheckPermission(perm Permission, permDependancies *Permission, internal bool) bool
BindRole(userID string, roleID string) (string, int, error)
BindGroup(userID string, groupID string) (string, int, error)
@@ -51,6 +55,11 @@ var c = map[string]PermConnector{
"keto": KetoConnector{},
}
func GetPermissionConnector() PermConnector {
return c["keto"]
func GetPermissionConnector(scope string) PermConnector {
for k := range c {
if strings.Contains(conf.GetConfig().PermissionConnectorReadHost, k) {
return c[k]
}
}
return nil
}

View File

@@ -1,21 +0,0 @@
version: '3.4'
services:
keto:
image: oryd/keto:v0.7.0-alpha.1-sqlite
ports:
- "4466:4466"
- "4467:4467"
command: serve -c /home/ory/keto.yml
restart: on-failure
volumes:
- type: bind
source: .
target: /home/ory
container_name: keto
networks:
- catalog
networks:
catalog:
external: true

View File

@@ -1,18 +0,0 @@
version: v0.6.0-alpha.1
log:
level: debug
namespaces:
- id: 0
name: open-cloud
dsn: memory
serve:
read:
host: 0.0.0.0
port: 4466
write:
host: 0.0.0.0
port: 4467

View File

@@ -1,79 +0,0 @@
version: "3"
services:
hydra-client:
image: oryd/hydra:v2.2.0
container_name: hydra-client
environment:
HYDRA_ADMIN_URL: http://hydra:4445
ORY_SDK_URL: http://hydra:4445
command:
- create
- oauth2-client
- --skip-tls-verify
- --name
- test-client
- --secret
- oc-auth-got-secret
- --response-type
- id_token,token,code
- --grant-type
- implicit,refresh_token,authorization_code,client_credentials
- --scope
- openid,profile,email,roles
- --token-endpoint-auth-method
- client_secret_post
- --redirect-uri
- http://localhost:3000
networks:
- hydra-net
- catalog
deploy:
restart_policy:
condition: none
depends_on:
- hydra
healthcheck:
test: ["CMD", "curl", "-f", "http://hydra:4445"]
interval: 10s
timeout: 10s
retries: 10
hydra:
container_name: hydra
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
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_CLAIMS: name,family_name,given_name,nickname,email,phone_number
DSN: memory
command: serve all --dev
networks:
- hydra-net
- catalog
ports:
- "4444:4444"
- "4445:4445"
deploy:
restart_policy:
condition: on-failure
ldap:
image: pgarrett/ldap-alpine
container_name: ldap
volumes:
- "./ldap.ldif:/ldif/ldap.ldif"
networks:
- hydra-net
- catalog
ports:
- "390:389"
deploy:
restart_policy:
condition: on-failure
networks:
hydra-net:
catalog:
external: true

View File

@@ -1,24 +0,0 @@
dn: uid=admin,ou=Users,dc=example,dc=com
objectClass: inetOrgPerson
cn: Admin
sn: Istrator
uid: admin
userPassword: admin
mail: admin@example.com
ou: Users
dn: ou=AppRoles,dc=example,dc=com
objectClass: organizationalunit
ou: AppRoles
description: AppRoles
dn: ou=App1,ou=AppRoles,dc=example,dc=com
objectClass: organizationalunit
ou: App1
description: App1
dn: cn=traveler,ou=App1,ou=AppRoles,dc=example,dc=com
objectClass: groupofnames
cn: traveler
description: traveler
member: uid=admin,ou=Users,dc=example,dc=com

199
main.go
View File

@@ -1,19 +1,26 @@
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"oc-auth/conf"
"oc-auth/infrastructure"
auth_connectors "oc-auth/infrastructure/auth_connector"
_ "oc-auth/routers"
"os"
"runtime/debug"
"strconv"
"strings"
"time"
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"
"github.com/i-core/rlog"
)
const appname = "oc-auth"
@@ -23,93 +30,165 @@ const appname = "oc-auth"
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.
func main() {
// Init the oc-lib
oclib.Init(appname)
oclib.InitAPI(appname)
// Load the right config file
o := oclib.GetConfLoader()
o := oclib.GetConfLoader(appname)
conf.GetConfig().AdminRole = o.GetStringDefault("ADMIN_ROLE", "admin")
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().OAuth2ClientSecretName = o.GetStringDefault("OAUTH2_CLIENT_SECRET_NAME", "oc-oauth2-client-secret")
conf.GetConfig().OAuth2ClientSecretNamespace = o.GetStringDefault("NAMESPACE", "default")
conf.GetConfig().Auth = o.GetStringDefault("AUTH", "hydra")
conf.GetConfig().AuthConnectorHost = o.GetStringDefault("AUTH_CONNECTOR_HOST", "localhost")
conf.GetConfig().AuthConnectPublicHost = o.GetStringDefault("AUTH_CONNECTOR_PUBLIC_HOST", "localhost")
conf.GetConfig().AuthConnectorPort = o.GetIntDefault("AUTH_CONNECTOR_PORT", 4444)
conf.GetConfig().AuthConnectorAdminPort = o.GetIntDefault("AUTH_CONNECTOR_ADMIN_PORT", 4445)
conf.GetConfig().PermissionConnectorHost = o.GetStringDefault("PERMISSION_CONNECTOR_HOST", "keto")
conf.GetConfig().PermissionConnectorPort = o.GetIntDefault("PERMISSION_CONNECTOR_PORT", 4466)
conf.GetConfig().PermissionConnectorAdminPort = o.GetIntDefault("PERMISSION_CONNECTOR_ADMIN_PORT", 4467)
conf.GetConfig().AuthConnectorAdminPort = o.GetStringDefault("AUTH_CONNECTOR_ADMIN_PORT", "4445/admin")
conf.GetConfig().PermissionConnectorWriteHost = o.GetStringDefault("PERMISSION_CONNECTOR_WRITE_HOST", "keto")
conf.GetConfig().PermissionConnectorReadHost = o.GetStringDefault("PERMISSION_CONNECTOR_READ_HOST", "keto")
conf.GetConfig().PermissionConnectorPort = o.GetStringDefault("PERMISSION_CONNECTOR_PORT", "4466")
conf.GetConfig().PermissionConnectorAdminPort = o.GetStringDefault("PERMISSION_CONNECTOR_ADMIN_PORT", "4467")
conf.GetConfig().Local = o.GetBoolDefault("LOCAL", true)
// config LDAP
conf.GetConfig().SourceMode = o.GetStringDefault("SOURCE_MODE", "ldap")
conf.GetConfig().LDAPEndpoints = o.GetStringDefault("LDAP_ENDPOINTS", "ldap:389")
conf.GetConfig().LDAPBindDN = o.GetStringDefault("LDAP_BINDDN", "cn=admin,dc=example,dc=com")
conf.GetConfig().LDAPBindPW = o.GetStringDefault("LDAP_BINDPW", "password")
conf.GetConfig().LDAPBaseDN = o.GetStringDefault("LDAP_BASEDN", "dc=example,dc=com")
conf.GetConfig().LDAPUserBaseDN = o.GetStringDefault("LDAP_USER_BASEDN", "ou=users,dc=example,dc=com")
conf.GetConfig().LDAPRoleBaseDN = o.GetStringDefault("LDAP_ROLE_BASEDN", "ou=AppRoles,dc=example,dc=com")
err := generateSelfPeer()
if err != nil {
panic(err)
}
discovery()
go generateSelfPeer()
go generateRole()
go discovery()
beego.Run()
}
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))
file := ""
f, err := os.ReadFile(conf.GetConfig().PublicKeyPath)
if err != nil {
return err
}
file = string(f)
if len(p.Data) > 0 {
// check public key with the one in the database
// compare the public key from file with the one in the database
if !strings.Contains(file, p.Data[0].(*peer.Peer).PublicKey) {
return errors.New("public key is different from the one in the database")
func generateRole() {
defer func() {
if r := recover(); r != nil {
fmt.Println("generateRole Recovered in f", r, debug.Stack())
}
}()
// if from ldap, create roles from ldap
if conf.GetConfig().SourceMode == "ldap" {
for {
ldap := auth_connectors.New()
roles, err := ldap.GetRoles(context.Background())
if err == nil {
fmt.Println("ROLE", roles)
for _, role := range roles {
for r, m := range role.Members {
infrastructure.GetPermissionConnector("").CreateRole(r)
for _, p := range m {
infrastructure.GetPermissionConnector("").BindRole(r, p)
}
}
}
break
} else {
time.Sleep(10 * time.Second) // Pause execution for 10 seconds
continue
}
}
return nil
}
// 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: file,
State: peer.SELF,
}
data := oclib.StoreOne(oclib.LibDataEnum(oclib.PEER), peer.Serialize())
if data.Err != "" {
return errors.New(data.Err)
}
func generateSelfPeer() error {
defer func() {
if r := recover(); r != nil {
fmt.Println("generateSelfPeer Recovered in f", r, debug.Stack())
}
}()
log := rlog.FromContext(context.Background()).Sugar()
for {
// 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.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).Search(nil, strconv.Itoa(peer.SELF.EnumIndex()), false)
file := ""
f, err := os.ReadFile(conf.GetConfig().PublicKeyPath)
if err != nil {
time.Sleep(10 * time.Second)
log.Error(err)
continue
}
file = string(f)
if len(p.Data) > 0 {
// check public key with the one in the database
// compare the public key from file with the one in the database
if !strings.Contains(file, p.Data[0].(*peer.Peer).PublicKey) {
return errors.New("public key is different from the one in the database")
}
return nil
}
// create a new peer
o := oclib.GetConfLoader(appname)
peer := &peer.Peer{
APIUrl: o.GetStringDefault("HOSTNAME", "http://localhost"),
NATSAddress: oclib.GetConfig().NATSUrl,
AbstractObject: utils.AbstractObject{
Name: o.GetStringDefault("NAME", "local"),
},
PublicKey: file,
Relation: peer.SELF,
State: peer.ONLINE,
WalletAddress: "my-wallet",
}
data := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).StoreOne(peer.Serialize(peer))
if data.Err != "" {
time.Sleep(10 * time.Second) // Pause execution for 10 seconds
log.Error(err)
continue
}
break
}
return nil
}
func discovery() {
api := tools.API{}
conn := infrastructure.GetPermissionConnector()
conn.CreateRole(conf.GetConfig().AdminRole)
conn.BindRole(conf.GetConfig().AdminRole, "admin")
addPermissions := func(m map[string]interface{}) {
for k, v := range m {
for _, p := range v.([]interface{}) {
conn.CreatePermission(k, p.(string), true)
defer func() {
if r := recover(); r != nil {
fmt.Println("discovery Recovered in f", r, debug.Stack())
}
}()
for {
api := tools.API{}
conn := infrastructure.GetPermissionConnector("")
fmt.Println("AdminRole", conn, conf.GetConfig().PermissionConnectorWriteHost)
_, _, err := conn.CreateRole(conf.GetConfig().AdminRole)
if err != nil {
time.Sleep(10 * time.Second) // Pause execution for 10 seconds
continue
}
conn.BindRole(conf.GetConfig().AdminRole, "admin")
addPermissions := func(m tools.NATSResponse) {
var resp map[string][]interface{}
json.Unmarshal(m.Payload, &resp)
for k, v := range resp {
for _, p := range v {
conn.CreatePermission(k, p.(string), true)
}
}
}
api.ListenRouter(addPermissions)
b, _ := json.Marshal(map[string]interface{}{})
tools.NewNATSCaller().SetNATSPub(tools.DISCOVERY, tools.NATSResponse{
FromApp: "oc-auth",
Datatype: -1,
User: "root",
Method: tools.GET.EnumIndex(),
Payload: b,
})
break
}
api.ListenRouter(addPermissions)
tools.NewNATSCaller().SetNATSPub("api", tools.DISCOVERY, map[string]interface{}{})
}

BIN
oc-auth Executable file

Binary file not shown.

View File

@@ -99,8 +99,8 @@ func init() {
beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"] = append(beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"],
beego.ControllerComments{
Method: "LoginLDAP",
Router: `/ldap/login`,
Method: "Login",
Router: `/login`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
@@ -108,8 +108,8 @@ func init() {
beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"] = append(beego.GlobalControllerRouter["oc-auth/controllers:OAuthController"],
beego.ControllerComments{
Method: "LogOutLDAP",
Router: `/ldap/logout`,
Method: "LogOut",
Router: `/logout`,
AllowHTTPMethods: []string{"delete"},
MethodParams: param.Make(),
Filters: nil,

View File

@@ -191,7 +191,7 @@
"parameters": [
{
"in": "path",
"name": "group_id",
"name": "user_id",
"description": "The group_id you want to unbind",
"required": true,
"type": "string"
@@ -233,7 +233,7 @@
}
}
},
"/ldap/login": {
"/login": {
"post": {
"tags": [
"oc-auth/controllersOAuthController"
@@ -249,6 +249,13 @@
"schema": {
"$ref": "#/definitions/models.workflow"
}
},
{
"in": "query",
"name": "client_id",
"description": "the client_id you want to get",
"required": true,
"type": "string"
}
],
"responses": {
@@ -258,7 +265,7 @@
}
}
},
"/ldap/logout": {
"/logout": {
"delete": {
"tags": [
"oc-auth/controllersOAuthController"
@@ -271,6 +278,13 @@
"name": "Authorization",
"description": "auth token",
"type": "string"
},
{
"in": "query",
"name": "client_id",
"description": "the client_id you want to get",
"required": true,
"type": "string"
}
],
"responses": {
@@ -465,6 +479,13 @@
"schema": {
"$ref": "#/definitions/models.Token"
}
},
{
"in": "query",
"name": "client_id",
"description": "the client_id you want to get",
"required": true,
"type": "string"
}
],
"responses": {

View File

@@ -119,7 +119,7 @@ paths:
operationId: GroupController.UnBind
parameters:
- in: path
name: group_id
name: user_id
description: The group_id you want to unbind
required: true
type: string
@@ -175,7 +175,7 @@ paths:
responses:
"200":
description: '{string}'
/ldap/login:
/login:
post:
tags:
- oc-auth/controllersOAuthController
@@ -190,10 +190,15 @@ paths:
required: true
schema:
$ref: '#/definitions/models.workflow'
- in: query
name: client_id
description: the client_id you want to get
required: true
type: string
responses:
"200":
description: '{string}'
/ldap/logout:
/logout:
delete:
tags:
- oc-auth/controllersOAuthController
@@ -206,6 +211,11 @@ paths:
name: Authorization
description: auth token
type: string
- in: query
name: client_id
description: the client_id you want to get
required: true
type: string
responses:
"200":
description: '{string}'
@@ -350,6 +360,11 @@ paths:
required: true
schema:
$ref: '#/definitions/models.Token'
- in: query
name: client_id
description: the client_id you want to get
required: true
type: string
responses:
"200":
description: '{string}'