Compare commits

...

1 Commits

Author SHA1 Message Date
mr
b84c2ef353 workin oc-auth 2025-01-17 17:24:08 +01:00
23 changed files with 551 additions and 104 deletions

View File

@ -3,6 +3,7 @@ package conf
import "sync" import "sync"
type Config struct { type Config struct {
SourceMode string
AdminRole string AdminRole string
PublicKeyPath string PublicKeyPath string
PrivateKeyPath string PrivateKeyPath string

View File

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

View File

@ -1,9 +1,11 @@
package controllers package controllers
import ( import (
"encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"oc-auth/conf"
"oc-auth/infrastructure" "oc-auth/infrastructure"
auth_connectors "oc-auth/infrastructure/auth_connector" auth_connectors "oc-auth/infrastructure/auth_connector"
"regexp" "regexp"
@ -22,10 +24,12 @@ type OAuthController struct {
// @Title Logout // @Title Logout
// @Description unauthenticate user // @Description unauthenticate user
// @Param Authorization header string false "auth token" // @Param Authorization header string false "auth token"
// @Param client_id query string true "the client_id you want to get"
// @Success 200 {string} // @Success 200 {string}
// @router /ldap/logout [delete] // @router /logout [delete]
func (o *OAuthController) LogOutLDAP() { func (o *OAuthController) LogOut() {
// authorize user // authorize user
clientID := o.Ctx.Input.Query("client_id")
reqToken := o.Ctx.Request.Header.Get("Authorization") reqToken := o.Ctx.Request.Header.Get("Authorization")
splitToken := strings.Split(reqToken, "Bearer ") splitToken := strings.Split(reqToken, "Bearer ")
if len(splitToken) < 2 { if len(splitToken) < 2 {
@ -36,7 +40,7 @@ func (o *OAuthController) LogOutLDAP() {
var res auth_connectors.Token var res auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res) json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res)
token, err := infrastructure.GetAuthConnector().Logout(reqToken) token, err := infrastructure.GetAuthConnector().Logout(clientID, reqToken)
if err != nil || token == nil { if err != nil || token == nil {
o.Data["json"] = err o.Data["json"] = err
} else { } else {
@ -48,25 +52,33 @@ func (o *OAuthController) LogOutLDAP() {
// @Title Login // @Title Login
// @Description authenticate user // @Description authenticate user
// @Param body body models.workflow true "The workflow content" // @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} // @Success 200 {string}
// @router /ldap/login [post] // @router /login [post]
func (o *OAuthController) LoginLDAP() { func (o *OAuthController) Login() {
// authorize user // authorize user
fmt.Println("Login", o.Ctx.Input.Query("client_id"), o.Ctx.Input.Param(":client_id"))
clientID := o.Ctx.Input.Query("client_id")
var res auth_connectors.Token var res auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res) json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res)
if conf.GetConfig().SourceMode == "ldap" {
ldap := auth_connectors.New() ldap := auth_connectors.New()
found, err := ldap.Authenticate(o.Ctx.Request.Context(), res.Username, res.Password) found, err := ldap.Authenticate(o.Ctx.Request.Context(), res.Username, res.Password)
fmt.Println("found", found, "err", err)
if err != nil || !found { if err != nil || !found {
o.Data["json"] = err o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401) o.Ctx.ResponseWriter.WriteHeader(401)
o.ServeJSON() o.ServeJSON()
return return
} }
token, err := infrastructure.GetAuthConnector().Login(res.Username, }
token, err := infrastructure.GetAuthConnector().Login(
clientID, res.Username,
&http.Cookie{ // open a session &http.Cookie{ // open a session
Name: "csrf_token", Name: "csrf_token",
Value: o.XSRFToken(), Value: o.XSRFToken(),
}) })
fmt.Println("token", token, "err", err)
if err != nil || token == nil { if err != nil || token == nil {
o.Data["json"] = err o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401) o.Ctx.ResponseWriter.WriteHeader(401)
@ -79,13 +91,15 @@ func (o *OAuthController) LoginLDAP() {
// @Title Introspection // @Title Introspection
// @Description introspect token // @Description introspect token
// @Param body body models.Token true "The token info" // @Param body body models.Token true "The token info"
// @Param client_id query string true "the client_id you want to get"
// @Success 200 {string} // @Success 200 {string}
// @router /refresh [post] // @router /refresh [post]
func (o *OAuthController) Refresh() { func (o *OAuthController) Refresh() {
clientID := o.Ctx.Input.Query("client_id")
var token auth_connectors.Token var token auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(100000), &token) json.Unmarshal(o.Ctx.Input.CopyBody(100000), &token)
// refresh token // refresh token
newToken, err := infrastructure.GetAuthConnector().Refresh(&token) newToken, err := infrastructure.GetAuthConnector().Refresh(clientID, &token)
if err != nil || newToken == nil { if err != nil || newToken == nil {
o.Data["json"] = err o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401) o.Ctx.ResponseWriter.WriteHeader(401)
@ -128,7 +142,7 @@ var whitelist = []string{
// @Param Authorization header string false "auth token" // @Param Authorization header string false "auth token"
// @Success 200 {string} // @Success 200 {string}
// @router /forward [get] // @router /forward [get]
func (o *OAuthController) InternalAuthForward() { func (o *OAuthController) InternaisDraftlAuthForward() {
fmt.Println("InternalAuthForward") fmt.Println("InternalAuthForward")
reqToken := o.Ctx.Request.Header.Get("Authorization") reqToken := o.Ctx.Request.Header.Get("Authorization")
if reqToken == "" { if reqToken == "" {
@ -149,7 +163,7 @@ func (o *OAuthController) InternalAuthForward() {
} else { } else {
reqToken = splitToken[1] reqToken = splitToken[1]
} }
origin, publicKey, external := o.extractOrigin() origin, publicKey, external := o.extractOrigin(o.Ctx.Request)
if !infrastructure.GetAuthConnector().CheckAuthForward( //reqToken != "" && if !infrastructure.GetAuthConnector().CheckAuthForward( //reqToken != "" &&
reqToken, publicKey, origin, reqToken, publicKey, origin,
o.Ctx.Request.Header.Get("X-Forwarded-Method"), o.Ctx.Request.Header.Get("X-Forwarded-Method"),
@ -161,7 +175,8 @@ func (o *OAuthController) InternalAuthForward() {
o.ServeJSON() 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 external := true
publicKey := "" publicKey := ""
origin := o.Ctx.Request.Header.Get("X-Forwarded-Host") origin := o.Ctx.Request.Header.Get("X-Forwarded-Host")
@ -174,7 +189,7 @@ func (o *OAuthController) extractOrigin() (string, string, bool) {
if t != "" { if t != "" {
searchStr = strings.Replace(searchStr, t, "", -1) searchStr = strings.Replace(searchStr, t, "", -1)
} }
peer := oclib.Search(nil, searchStr, oclib.LibDataEnum(oclib.PEER)) peer := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).Search(nil, searchStr, false)
if peer.Code != 200 || len(peer.Data) == 0 { // TODO: add state of partnership if peer.Code != 200 || len(peer.Data) == 0 { // TODO: add state of partnership
return "", "", external return "", "", external
} }
@ -190,3 +205,29 @@ func (o *OAuthController) extractOrigin() (string, string, bool) {
} }
return origin, publicKey, external 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 // @Success 200 {permission} string
// @router / [get] // @router / [get]
func (o *PermissionController) GetAll() { func (o *PermissionController) GetAll() {
role, err := infrastructure.GetPermissionConnector().GetPermission("", "") clientID := ExtractClient(*o.Ctx.Request)
role, err := infrastructure.GetPermissionConnector(clientID).GetPermission("", "")
if err != nil { if err != nil {
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": nil, "data": nil,
@ -41,7 +42,8 @@ func (o *PermissionController) GetAll() {
// @router /role/:id [get] // @router /role/:id [get]
func (o *PermissionController) GetByRole() { func (o *PermissionController) GetByRole() {
id := o.Ctx.Input.Param(":id") 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 { if err != nil {
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": nil, "data": nil,
@ -66,7 +68,8 @@ func (o *PermissionController) GetByRole() {
// @router /user/:id [get] // @router /user/:id [get]
func (o *PermissionController) GetByUser() { func (o *PermissionController) GetByUser() {
id := o.Ctx.Input.Param(":id") 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 { if err != nil {
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": nil, "data": nil,
@ -92,7 +95,8 @@ func (o *PermissionController) GetByUser() {
func (o *PermissionController) Get() { func (o *PermissionController) Get() {
id := o.Ctx.Input.Param(":id") id := o.Ctx.Input.Param(":id")
rel := o.Ctx.Input.Param(":relation") 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 { if err != nil {
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": nil, "data": nil,
@ -115,7 +119,8 @@ func (o *PermissionController) Get() {
// @Success 200 {string} delete success! // @Success 200 {string} delete success!
// @router /clear [delete] // @router /clear [delete]
func (o *PermissionController) Clear() { 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 { if err != nil {
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": nil, "data": nil,
@ -144,7 +149,8 @@ func (o *PermissionController) Bind() {
permission_id := o.Ctx.Input.Param(":permission_id") permission_id := o.Ctx.Input.Param(":permission_id")
role_id := o.Ctx.Input.Param(":role_id") role_id := o.Ctx.Input.Param(":role_id")
rel := o.Ctx.Input.Param(":relation") 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 { if err != nil {
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": nil, "data": nil,
@ -173,7 +179,8 @@ func (o *PermissionController) UnBind() {
permission_id := o.Ctx.Input.Param(":permission_id") permission_id := o.Ctx.Input.Param(":permission_id")
role_id := o.Ctx.Input.Param(":role_id") role_id := o.Ctx.Input.Param(":role_id")
rel := o.Ctx.Input.Param(":relation") 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 { if err != nil {
o.Data["json"] = map[string]interface{}{ o.Data["json"] = map[string]interface{}{
"data": nil, "data": nil,

View File

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

21
docker-compose-2.yml Normal file
View File

@ -0,0 +1,21 @@
version: '3.4'
services:
oc-auth-2:
image: 'oc-auth-2:latest'
ports:
- 8095:8080
container_name: oc-auth-2
environment:
LDAP_ENDPOINTS: ldap-2:389
LDAP_BINDDN: cn=admin,dc=example,dc=com
LDAP_BINDPW: password
LDAP_BASEDN: "dc=example,dc=com"
LDAP_ROLE_BASEDN: "ou=AppRoles,dc=example,dc=com"
networks:
- catalog
volumes:
- ./pem:/etc/oc/pem
networks:
catalog:
external: true

5
go.mod
View File

@ -3,7 +3,7 @@ module oc-auth
go 1.22.0 go 1.22.0
require ( require (
cloud.o-forge.io/core/oc-lib v0.0.0-20241121074503-15ca06aba883 cloud.o-forge.io/core/oc-lib v0.0.0-20250117152246-b85ca8674b27
github.com/beego/beego/v2 v2.3.1 github.com/beego/beego/v2 v2.3.1
github.com/nats-io/nats.go v1.37.0 github.com/nats-io/nats.go v1.37.0
github.com/ory/hydra-client-go v1.11.8 github.com/ory/hydra-client-go v1.11.8
@ -15,6 +15,7 @@ require (
require ( require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/biter777/countries v1.7.5 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
@ -36,6 +37,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/marcinwyszynski/geopoint v0.0.0-20140302213024-cf2a6f750c5b // indirect
github.com/mattn/goveralls v0.0.12 // indirect github.com/mattn/goveralls v0.0.12 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
@ -44,6 +46,7 @@ require (
github.com/ory/x v0.0.575 // indirect github.com/ory/x v0.0.575 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/robfig/cron v1.2.0 // indirect
github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/afero v1.9.5 // indirect github.com/spf13/afero v1.9.5 // indirect

78
go.sum
View File

@ -35,6 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.o-forge.io/core/oc-lib v0.0.0-20240904135449-4f0ab6a3760f h1:v9mw3uNg/DJswOvHooMu8/BMedA+vIXbma+8iUwsjUI=
cloud.o-forge.io/core/oc-lib v0.0.0-20240904135449-4f0ab6a3760f/go.mod h1:FIJD0taWLJ5pjQLJ6sfE2KlTkvbmk5SMcyrxdjsaVz0=
cloud.o-forge.io/core/oc-lib v0.0.0-20241016115009-b43226648692 h1:cfRhQioLwTBg9h1OOOp3VcUsBChO97M9lRDP8aq2Gkk= cloud.o-forge.io/core/oc-lib v0.0.0-20241016115009-b43226648692 h1:cfRhQioLwTBg9h1OOOp3VcUsBChO97M9lRDP8aq2Gkk=
cloud.o-forge.io/core/oc-lib v0.0.0-20241016115009-b43226648692/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8= cloud.o-forge.io/core/oc-lib v0.0.0-20241016115009-b43226648692/go.mod h1:t+zpCTVKVdHH/BImwtMYY2QIWLMXKgY4n/JhFm3Vpu8=
cloud.o-forge.io/core/oc-lib v0.0.0-20241016151521-9654d59fc076 h1:kPIBXPWdO47YdZClB/QYkt3EaReYS7Gs/c4FSXzhjtI= cloud.o-forge.io/core/oc-lib v0.0.0-20241016151521-9654d59fc076 h1:kPIBXPWdO47YdZClB/QYkt3EaReYS7Gs/c4FSXzhjtI=
@ -99,6 +101,76 @@ cloud.o-forge.io/core/oc-lib v0.0.0-20241121071546-e9b3a65a0ec6 h1:AdUkzaX63VF3f
cloud.o-forge.io/core/oc-lib v0.0.0-20241121071546-e9b3a65a0ec6/go.mod h1:ya7Q+zHhaKM+XF6sAJ+avqHEVzaMnFJQih2X3TlTlGo= cloud.o-forge.io/core/oc-lib v0.0.0-20241121071546-e9b3a65a0ec6/go.mod h1:ya7Q+zHhaKM+XF6sAJ+avqHEVzaMnFJQih2X3TlTlGo=
cloud.o-forge.io/core/oc-lib v0.0.0-20241121074503-15ca06aba883 h1:JdHJT8vuup4pJCC7rjiOe0/qD7at6400ml5zZHjEeUo= cloud.o-forge.io/core/oc-lib v0.0.0-20241121074503-15ca06aba883 h1:JdHJT8vuup4pJCC7rjiOe0/qD7at6400ml5zZHjEeUo=
cloud.o-forge.io/core/oc-lib v0.0.0-20241121074503-15ca06aba883/go.mod h1:ya7Q+zHhaKM+XF6sAJ+avqHEVzaMnFJQih2X3TlTlGo= cloud.o-forge.io/core/oc-lib v0.0.0-20241121074503-15ca06aba883/go.mod h1:ya7Q+zHhaKM+XF6sAJ+avqHEVzaMnFJQih2X3TlTlGo=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202081145-cb21db672bb5 h1:qxXC6fkEa8bLTo0qn3VrB55tfxyjHQQa/0n97piJhNI=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202081145-cb21db672bb5/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202121923-2ec6899a1865 h1:BhGzhy6gsEA7vthuq6KWyABsRuF4KV5NqOvfkygytGg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202121923-2ec6899a1865/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202134851-9a2ed2351d7e h1:3U5JBdQRti2OpALLPhev6lkUi1TlYHgo2ADidOAfEAs=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202134851-9a2ed2351d7e/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202152644-e2ddd7e4e6f9 h1:qUA6T5Pjq/pv6dZYH4PWktXmFiRnloDX84m1U5NhvLM=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202152644-e2ddd7e4e6f9/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202155908-599a6144803e h1:3xGLiTDTgWHIIPDZyTo/clMIj+gQxnIDSE78s9/0wNE=
cloud.o-forge.io/core/oc-lib v0.0.0-20241202155908-599a6144803e/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203073336-6042d47700fd h1:iDryCORnODgAvBe1Yi+RnIGjYgUSkAv7ZCnm+CUV18w=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203073336-6042d47700fd/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203082527-2924ccd23b5c h1:3ghuxLEI3JXicDYoFx4YnkLauLl0Nq9UErjpL/2SqEU=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203082527-2924ccd23b5c/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203090110-471e0c9d9b48 h1:kVTpROPipS4YtROH9vAGZw21OMLNR48qbYedCngGThw=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203090110-471e0c9d9b48/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203095728-ea55c94c7328 h1:7iK2HzMm0EEEF60ajUVT/6jwqIirduww5Xa3191XS4I=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203095728-ea55c94c7328/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203105751-4b88da8ff66d h1:iIo+AMQ09MshkKKN8K8pd1ooLaigAYlnUUnQAaCidLo=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203105751-4b88da8ff66d/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203115141-6681c455d8e0 h1:RnHCONn0oYbEaTN1wDIeOAEM12cCZQRtvjBCVCb0b1Y=
cloud.o-forge.io/core/oc-lib v0.0.0-20241203115141-6681c455d8e0/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241204103308-fd01f535a131 h1:FdUY8b8xTdVzQ9wlphlo8TlbQif76V9oxGDYq26TsAs=
cloud.o-forge.io/core/oc-lib v0.0.0-20241204103308-fd01f535a131/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241204111455-1fcbc7c08ab0 h1:cBr4m2tcLf+dZufrjYvhvcsSqXcRDeyhnq5c5HY15po=
cloud.o-forge.io/core/oc-lib v0.0.0-20241204111455-1fcbc7c08ab0/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20241205082103-fbbce7817b73 h1:g96KMOxdhvM7x6YFqJfd08wybRzCLEvol7HfhKJfxO4=
cloud.o-forge.io/core/oc-lib v0.0.0-20241205082103-fbbce7817b73/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20250110164331-5255ffc2f728 h1:3p1G82xZmEAu2OEyY5HM42Cfbb1J887P9lSoRKNhgg8=
cloud.o-forge.io/core/oc-lib v0.0.0-20250110164331-5255ffc2f728/go.mod h1:2IevepXviessA6m67fB6ZJhZSeEeoOYWbVqPS4dzkbg=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113102407-21a7ff90104a h1:rrLSuAHI/TGOTm5d7Bffu+qf4EnmPguOll5x5nG/3Tc=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113102407-21a7ff90104a/go.mod h1:VgWEn23ddKySWXrwPMhqtiBjTJnbm5t7yWjzfvNxbbI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113114256-11905339bb24 h1:Kc51xKbnyfeafHpOJP7mWh9InNGqZUwcJR46008D+Eg=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113114256-11905339bb24/go.mod h1:VgWEn23ddKySWXrwPMhqtiBjTJnbm5t7yWjzfvNxbbI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113124812-6e5c87379649 h1:dmtrmNDdTR/2R3HjaIbPdu5LZViPzigwSjU207NXCxI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113124812-6e5c87379649/go.mod h1:VgWEn23ddKySWXrwPMhqtiBjTJnbm5t7yWjzfvNxbbI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113135241-a0f436b3e162 h1:oGP40P/uUngU7stnsRdx0jwxZGc+pzLzrMlUjEBSy0M=
cloud.o-forge.io/core/oc-lib v0.0.0-20250113135241-a0f436b3e162/go.mod h1:VgWEn23ddKySWXrwPMhqtiBjTJnbm5t7yWjzfvNxbbI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114071722-1c32cd2d12df h1:T52jgXQddoxwe+embR26Fwmz4G2jkl4QpYVHGtiLUNI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114071722-1c32cd2d12df/go.mod h1:VgWEn23ddKySWXrwPMhqtiBjTJnbm5t7yWjzfvNxbbI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114081637-918006302bb4 h1:AwCbDHjvUz9iQaF7hgYWyabVF/EzSSSk5bCNgntNJ6c=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114081637-918006302bb4/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114105339-b782248da741 h1:akAQLlcAXDtUhbNHbona9xJrHCzK9jxlvsDsEpVP1fg=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114105339-b782248da741/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114135055-1a4694c8913a h1:AxnecA1YKOZ81OKb1akK2Qc/0UNDUxdjSww7ALyehas=
cloud.o-forge.io/core/oc-lib v0.0.0-20250114135055-1a4694c8913a/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250115082026-ad69c0495144 h1:MZ90rw4SKL0dqL/Lb+7E54vkk9fb8W6X0UJo9UW/XBk=
cloud.o-forge.io/core/oc-lib v0.0.0-20250115082026-ad69c0495144/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250115095644-be3803039583 h1:6My1sqjvqgHnC4TlE7RsZQHC8AVhad0gZl8uOvLTM9o=
cloud.o-forge.io/core/oc-lib v0.0.0-20250115095644-be3803039583/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250115102820-0e0540af43d0 h1:AcHC2WIeHOSjz5xe7OsjMi39EevxdY2O/9q0VMkDRz0=
cloud.o-forge.io/core/oc-lib v0.0.0-20250115102820-0e0540af43d0/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250116091455-68f418928395 h1:u4myLPGqBbzprWHg6713k5a++4yiq1ujlVy7yrMkZ9g=
cloud.o-forge.io/core/oc-lib v0.0.0-20250116091455-68f418928395/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250116142544-a4a249bab828 h1:yMDBDTs7LECyueUfh0iug502GN8GodVpQSl/gZchUjU=
cloud.o-forge.io/core/oc-lib v0.0.0-20250116142544-a4a249bab828/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117081640-450fab437cb7 h1:SV9U48sR09cNRl48489lQHrrKJFtTMQoQcRhmtsLTYQ=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117081640-450fab437cb7/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117090737-b990fe42d375 h1:UsPWfbVgvUcOC3BtD8B9dUQfv/FnRF4IZGrYxUJr1iM=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117090737-b990fe42d375/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117100508-d44fb976e4ff h1:GaLrVn6ame6BV7pfUB2xeHCCJLBECRiCCpPj6zteL+s=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117100508-d44fb976e4ff/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117121920-ed787683f47b h1:3wap+dPPplJkDglE5toKfdFUmjobAeIJWdiRtCQ3xkQ=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117121920-ed787683f47b/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117124801-e5c7dbe4cb96 h1:opQ/Uku27DOKAqDcKC9k6J9H5Tj9bNyKdHnJnD3U850=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117124801-e5c7dbe4cb96/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117135417-c63a1fef6c48 h1:dEebv8ZV5rt6BYPkcK6HOts+OPqkSxkKp5zn1lCq1vs=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117135417-c63a1fef6c48/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117152246-b85ca8674b27 h1:QEIj90eIoYsjs1uekbI3Nu48KDWmzGV7ugcr9agJbYI=
cloud.o-forge.io/core/oc-lib v0.0.0-20250117152246-b85ca8674b27/go.mod h1:2roQbUpv3a6mTIr5oU1ux31WbN8YucyyQvCQ0FqwbcE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
@ -115,6 +187,8 @@ github.com/beego/beego/v2 v2.3.2/go.mod h1:5cqHsOHJIxkq44tBpRvtDe59GuVRVv/9/tyVD
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 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/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/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -405,6 +479,8 @@ github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQ
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/marcinwyszynski/geopoint v0.0.0-20140302213024-cf2a6f750c5b h1:XBF8THPBy28s2ryI7+/Jf/847unLWxYMpJveX5Kox+0=
github.com/marcinwyszynski/geopoint v0.0.0-20140302213024-cf2a6f750c5b/go.mod h1:z1oqhOuuYpPHmUmAK2aNygKFlPdb4o3PppQnVTRFdrI=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@ -486,6 +562,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/purnaresa/bulwark v0.0.0-20201001150757-1cec324746b2 h1:5w7Y/+01L0ErOp3qFiiAEpVlvzYJK2mjbLFcbBkx2OI= github.com/purnaresa/bulwark v0.0.0-20201001150757-1cec324746b2 h1:5w7Y/+01L0ErOp3qFiiAEpVlvzYJK2mjbLFcbBkx2OI=
github.com/purnaresa/bulwark v0.0.0-20201001150757-1cec324746b2/go.mod h1:/fUyI4rS5nHkKtgxNRU/uuFyhx9woSy3wKQSCQjqWN4= github.com/purnaresa/bulwark v0.0.0-20201001150757-1cec324746b2/go.mod h1:/fUyI4rS5nHkKtgxNRU/uuFyhx9woSy3wKQSCQjqWN4=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=

View File

@ -9,10 +9,10 @@ import (
type AuthConnector interface { type AuthConnector interface {
Status() tools.State Status() tools.State
Login(username string, cookies ...*http.Cookie) (*Token, error) Login(clientID string, username string, cookies ...*http.Cookie) (*Token, error)
Logout(token string, cookies ...*http.Cookie) (*Token, error) Logout(clientID string, token string, cookies ...*http.Cookie) (*Token, error)
Introspect(token string, cookie ...*http.Cookie) (bool, error) Introspect(token string, cookie ...*http.Cookie) (bool, error)
Refresh(token *Token) (*Token, error) Refresh(client_id string, token *Token) (*Token, error)
CheckAuthForward(reqToken string, publicKey string, host string, method string, forward string, external bool) bool CheckAuthForward(reqToken string, publicKey string, host string, method string, forward string, external bool) bool
} }

View File

@ -23,7 +23,6 @@ import (
type HydraConnector struct { type HydraConnector struct {
State string `json:"state"` State string `json:"state"`
Scopes string `json:"scope"` Scopes string `json:"scope"`
ClientID string `json:"client_id"`
ResponseType string `json:"response_type"` ResponseType string `json:"response_type"`
Caller *tools.HTTPCaller Caller *tools.HTTPCaller
@ -85,7 +84,7 @@ func (a HydraConnector) challenge(username string, url string, challenge string,
return &token, s[1], cookies, nil 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, ".") access := strings.Split(token.AccessToken, ".")
if len(access) > 2 { if len(access) > 2 {
token.AccessToken = strings.Join(access[0:2], ".") token.AccessToken = strings.Join(access[0:2], ".")
@ -94,11 +93,11 @@ func (a HydraConnector) Refresh(token *Token) (*Token, error) {
if err != nil || !isValid { if err != nil || !isValid {
return nil, err return nil, err
} }
_, err = a.Logout(token.AccessToken) _, err = a.Logout(client_id, token.AccessToken)
if err != nil { if err != nil {
return nil, err 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) { func (a HydraConnector) tryLog(username string, url string, subpath string, challenge string, cookies ...*http.Cookie) (*Redirect, string, []*http.Cookie, error) {
@ -120,7 +119,7 @@ func (a HydraConnector) tryLog(username string, url string, subpath string, chal
return a.challenge(username, resp.Request.URL.String(), challenge, cookies...) return a.challenge(username, resp.Request.URL.String(), challenge, cookies...)
} }
func (a HydraConnector) getClient() string { func (a HydraConnector) getClient(clientID string) string {
resp, err := a.Caller.CallGet(a.getPath(true, false), "/clients") resp, err := a.Caller.CallGet(a.getPath(true, false), "/clients")
if err != nil { if err != nil {
return "" return ""
@ -130,11 +129,17 @@ func (a HydraConnector) getClient() string {
if err != nil || len(clients) == 0 { if err != nil || len(clients) == 0 {
return "" 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) return clients[0].(map[string]interface{})["client_id"].(string)
} }
func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Token, err error) { func (a HydraConnector) Login(clientID string, username string, cookies ...*http.Cookie) (t *Token, err error) {
clientID := a.getClient() fmt.Println("login", clientID, username)
clientID = a.getClient(clientID)
redirect, _, cookies, err := a.tryLog(username, a.getPath(false, true), redirect, _, cookies, err := a.tryLog(username, a.getPath(false, true),
"/auth?client_id="+clientID+"&response_type="+strings.ReplaceAll(a.ResponseType, " ", "%20")+"&scope="+strings.ReplaceAll(a.Scopes, " ", "%20")+"&state="+a.State, "/auth?client_id="+clientID+"&response_type="+strings.ReplaceAll(a.ResponseType, " ", "%20")+"&scope="+strings.ReplaceAll(a.Scopes, " ", "%20")+"&state="+a.State,
"login", cookies...) "login", cookies...)
@ -176,7 +181,7 @@ func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Toke
return nil, err return nil, err
} }
json.Unmarshal(b, &m) 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 != "" { if len(pp.Data) == 0 || pp.Code >= 300 || pp.Err != "" {
return nil, errors.New("peer not found") return nil, errors.New("peer not found")
} }
@ -184,7 +189,8 @@ func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Toke
now = now.Add(time.Duration(token.ExpiresIn) * time.Second) now = now.Add(time.Duration(token.ExpiresIn) * time.Second)
unix := now.Unix() unix := now.Unix()
c := claims.GetClaims().AddClaimsToToken(username, pp.Data[0].(*peer.Peer)) c := claims.GetClaims().AddClaimsToToken(clientID, username, pp.Data[0].(*peer.Peer))
fmt.Println("claims", c.Session.AccessToken)
c.Session.AccessToken["exp"] = unix c.Session.AccessToken["exp"] = unix
b, _ = json.Marshal(c) b, _ = json.Marshal(c)
@ -194,7 +200,8 @@ func (a HydraConnector) Login(username string, cookies ...*http.Cookie) (t *Toke
return token, nil 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, ".") access := strings.Split(token, ".")
if len(access) > 2 { if len(access) > 2 {
token = strings.Join(access[0:2], ".") token = strings.Join(access[0:2], ".")
@ -202,7 +209,7 @@ func (a HydraConnector) Logout(token string, cookies ...*http.Cookie) (*Token, e
p := a.getPath(false, true) + "/revoke" p := a.getPath(false, true) + "/revoke"
urls := url.Values{} urls := url.Values{}
urls.Add("token", token) urls.Add("token", token)
urls.Add("client_id", a.getClient()) urls.Add("client_id", clientID)
urls.Add("client_secret", conf.GetConfig().ClientSecret) urls.Add("client_secret", conf.GetConfig().ClientSecret)
_, err := a.Caller.CallForm(http.MethodPost, p, "", urls, "application/x-www-form-urlencoded", true) _, err := a.Caller.CallForm(http.MethodPost, p, "", urls, "application/x-www-form-urlencoded", true)
if err != nil { if err != nil {

View File

@ -31,8 +31,9 @@ var (
type conn interface { type conn interface {
Bind(bindDN, password string) error Bind(bindDN, password string) error
SearchUser(user string, attrs ...string) ([]map[string]interface{}, error) SearchRoles(attrs ...string) ([]map[string][]string, error)
SearchUserRoles(user string, attrs ...string) ([]map[string]interface{}, error) SearchUser(user string, attrs ...string) ([]map[string][]string, error)
SearchUserRoles(user string, attrs ...string) ([]map[string][]string, error)
Close() error Close() error
} }
@ -78,7 +79,7 @@ type Client struct {
cache *freecache.Cache 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 == "" { if username == "" || password == "" {
return false, nil return false, nil
} }
@ -101,8 +102,8 @@ func (cli *Client) Authenticate(ctx context.Context, username, password string)
if details == nil { if details == nil {
return false, nil return false, nil
} }
a := details["dn"]
if err := cn.Bind(details["dn"].(string), password); err != nil { if err := cn.Bind(a[0], password); err != nil {
if err == errInvalidCredentials { if err == errInvalidCredentials {
return false, nil return false, nil
} }
@ -118,6 +119,21 @@ func (cli *Client) Authenticate(ctx context.Context, username, password string)
return true, nil 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 // Claim is the FindOIDCClaims result struct
type LDAPClaim struct { type LDAPClaim struct {
Code string // the root claim name Code string // the root claim name
@ -125,6 +141,10 @@ type LDAPClaim struct {
Value interface{} // the value Value interface{} // the value
} }
type LDAPRoles struct {
Members map[string][]string
}
// FindOIDCClaims finds all OIDC claims for a user. // FindOIDCClaims finds all OIDC claims for a user.
func (cli *Client) FindOIDCClaims(ctx context.Context, username string) ([]LDAPClaim, error) { func (cli *Client) FindOIDCClaims(ctx context.Context, username string) ([]LDAPClaim, error) {
if username == "" { if username == "" {
@ -193,11 +213,12 @@ func (cli *Client) FindOIDCClaims(ctx context.Context, username string) ([]LDAPC
roles := make(map[string]interface{}) roles := make(map[string]interface{})
for _, entry := range entries { for _, entry := range entries {
roleDN, ok := entry["dn"].(string) roleDNs, ok := entry["dn"]
if !ok || roleDN == "" { if !ok || len(roleDNs) == 0 {
log.Infow("No required LDAP attribute for a role", "ldapAttribute", "dn", "entry", entry) log.Infow("No required LDAP attribute for a role", "ldapAttribute", "dn", "entry", entry)
continue continue
} }
roleDN := roleDNs[0]
if entry[cli.RoleAttr] == nil { if entry[cli.RoleAttr] == nil {
log.Infow("No required LDAP attribute for a role", "ldapAttribute", cli.RoleAttr, "roleDN", roleDN) log.Infow("No required LDAP attribute for a role", "ldapAttribute", cli.RoleAttr, "roleDN", roleDN)
continue continue
@ -278,8 +299,79 @@ func (cli *Client) connect(ctx context.Context) <-chan conn {
return ch return ch
} }
func (cli *Client) findRoles(cn conn, attrs ...string) (map[string]LDAPRoles, error) {
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) {
panic("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. // 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) {
if cli.BindDN != "" { if cli.BindDN != "" {
// We need to login to a LDAP server with a service account for retrieving user data. // 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 { if err := cn.Bind(cli.BindDN, cli.BindPass); err != nil {
@ -298,7 +390,7 @@ func (cli *Client) findBasicUserDetails(cn conn, username string, attrs []string
var ( var (
entry = entries[0] entry = entries[0]
details = make(map[string]interface{}) details = make(map[string][]string)
) )
for _, attr := range attrs { for _, attr := range attrs {
if v, ok := entry[attr]; ok { if v, ok := entry[attr]; ok {
@ -349,35 +441,40 @@ func (c *ldapConn) Bind(bindDN, password string) error {
return err 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( query := fmt.Sprintf(
"(&(|(objectClass=organizationalPerson)(objectClass=inetOrgPerson))"+ "(&(|(objectClass=organizationalPerson)(objectClass=inetOrgPerson))"+
"(|(uid=%[1]s)(mail=%[1]s)(userPrincipalName=%[1]s)(sAMAccountName=%[1]s)))", user) "(|(uid=%[1]s)(mail=%[1]s)(userPrincipalName=%[1]s)(sAMAccountName=%[1]s)))", user)
return c.searchEntries(c.BaseDN, query, attrs) return c.searchEntries(c.BaseDN, 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("(|"+ query := fmt.Sprintf("(|"+
"(&(|(objectClass=group)(objectClass=groupOfNames))(member=%[1]s))"+ "(&(|(objectClass=group)(objectClass=groupOfNames)(objectClass=groupofnames))(member=%[1]s))"+
"(&(objectClass=groupOfUniqueNames)(uniqueMember=%[1]s))"+ "(&(objectClass=groupOfUniqueNames)(uniqueMember=%[1]s))"+
")", user) ")", user)
return c.searchEntries(c.RoleBaseDN, query, attrs) 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. // 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) {
req := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, query, attrs, nil) req := ldap.NewSearchRequest(baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, query, attrs, nil)
res, err := c.Search(req) res, err := c.Search(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var entries []map[string]interface{} var entries []map[string][]string
for _, v := range res.Entries { for _, v := range res.Entries {
entry := map[string]interface{}{"dn": v.DN} entry := map[string][]string{"dn": []string{v.DN}}
for _, attr := range v.Attributes { for _, attr := range v.Attributes {
// We need the first value only for the named attribute. // 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) entries = append(entries, entry)
} }

View File

@ -8,7 +8,7 @@ import (
// Tokenizer interface // Tokenizer interface
type ClaimService 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) DecodeClaimsInToken(host string, method string, forward string, sessionClaims Claims, publicKey string, external bool) (bool, error)
} }

View File

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

View File

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

View File

@ -6,24 +6,29 @@ import (
"fmt" "fmt"
"oc-auth/conf" "oc-auth/conf"
"oc-auth/infrastructure/utils" "oc-auth/infrastructure/utils"
"strings"
oclib "cloud.o-forge.io/core/oc-lib" oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/tools" "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 { func (k KetoConnector) namespace() string {
return "open-cloud" return "open-cloud"
} }
func (k KetoConnector) scope() string { func (k KetoConnector) scope() string {
return "oc-auth" return "oc-auth-realm"
} }
func (f KetoConnector) permToQuery(perm Permission, permDependancies *Permission) string { func (f KetoConnector) permToQuery(perm Permission, permDependancies *Permission) string {
n := "?namespace=" + perm.Namespace() n := "?namespace=" + f.namespace()
if perm.Object != "" { if perm.Object != "" {
n += "&object=" + perm.Object n += "&object=" + perm.Object
} }
@ -189,6 +194,7 @@ func (k KetoConnector) GetPermissionByRole(roleID string) ([]Permission, error)
} }
func (k KetoConnector) GetPermissionByUser(userID string, internal bool) ([]Permission, error) { func (k KetoConnector) GetPermissionByUser(userID string, internal bool) ([]Permission, error) {
roles, err := k.get("", "member", userID) roles, err := k.get("", "member", userID)
fmt.Println("ROLES", roles, err)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -235,7 +241,7 @@ func (k KetoConnector) get(object string, relation string, subject string) ([]Pe
return t, nil 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) _, code, err := k.createRelationShip(object, relation, subject, nil)
if err != nil { if err != nil {
return object, code, err return object, code, err
@ -244,6 +250,7 @@ func (k KetoConnector) binds(subject string, relation string, object string) (st
} }
func (k KetoConnector) BindRole(userID string, roleID string) (string, int, error) { func (k KetoConnector) BindRole(userID string, roleID string) (string, int, error) {
fmt.Println("BIND ROLE", userID, roleID)
return k.binds(userID, "member", roleID) return k.binds(userID, "member", roleID)
} }
@ -324,9 +331,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) { func (k KetoConnector) createRelationShip(object string, relation string, subject string, subPerm *Permission) (*Permission, int, error) {
exist, err := k.get(object, relation, subject) 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 { if err == nil && len(exist) > 0 {
return nil, 409, errors.New("Relation already exist") return nil, 409, errors.New("Relation already exist")
} }
@ -338,7 +342,7 @@ func (k KetoConnector) createRelationShip(object string, relation string, subjec
if err != nil { if err != nil {
return nil, code, err 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().PermissionConnectorHost host := conf.GetConfig().PermissionConnectorHost
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorAdminPort) port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorAdminPort)

View File

@ -23,6 +23,7 @@ func (k Permission) Scope() string {
type PermConnector interface { type PermConnector interface {
Status() tools.State Status() tools.State
SetClient(scope string)
CheckPermission(perm Permission, permDependancies *Permission, internal bool) bool CheckPermission(perm Permission, permDependancies *Permission, internal bool) bool
BindRole(userID string, roleID string) (string, int, error) BindRole(userID string, roleID string) (string, int, error)
BindGroup(userID string, groupID string) (string, int, error) BindGroup(userID string, groupID string) (string, int, error)
@ -53,6 +54,6 @@ var c = map[string]PermConnector{
"keto": KetoConnector{}, "keto": KetoConnector{},
} }
func GetPermissionConnector() PermConnector { func GetPermissionConnector(scope string) PermConnector {
return c[conf.GetConfig().PermissionConnectorHost] return c[conf.GetConfig().PermissionConnectorHost]
} }

View File

@ -0,0 +1,78 @@
version: "3"
services:
hydra-client-2:
image: oryd/hydra:v2.2.0
container_name: hydra-client-2
environment:
HYDRA_ADMIN_URL: http://hydra-2:4445
ORY_SDK_URL: http://hydra-2: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-2
healthcheck:
test: ["CMD", "curl", "-f", "http://hydra-2:4445"]
interval: 10s
timeout: 10s
retries: 10
hydra-2:
container_name: hydra-2
image: oryd/hydra:v2.2.0
environment:
SECRETS_SYSTEM: oc-auth-got-secret
LOG_LEAK_SENSITIVE_VALUES: true
URLS_SELF_ISSUER: http://hydra-2:4444
URLS_SELF_PUBLIC: http://hydra-2: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:
- "4446:4444"
- "4447:4445"
deploy:
restart_policy:
condition: on-failure
ldap-2:
image: pgarrett/ldap-alpine
container_name: ldap-2
volumes:
- "./ldap-2.ldif:/ldif/ldap.ldif"
networks:
- hydra-net
- catalog
ports:
- "389:389"
deploy:
restart_policy:
condition: on-failure
networks:
hydra-net:
catalog:
external: true

24
ldap-hydra/ldap-2.ldif Normal file
View File

@ -0,0 +1,24 @@
dn: uid=admin2,ou=Users,dc=example,dc=com
objectClass: inetOrgPerson
cn: Admin2
sn: Istrator
uid: admin2
userPassword: admin2
mail: admin2@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=admin2,ou=Users,dc=example,dc=com

36
main.go
View File

@ -1,9 +1,12 @@
package main package main
import ( import (
"context"
"errors" "errors"
"fmt"
"oc-auth/conf" "oc-auth/conf"
"oc-auth/infrastructure" "oc-auth/infrastructure"
auth_connectors "oc-auth/infrastructure/auth_connector"
_ "oc-auth/routers" _ "oc-auth/routers"
"os" "os"
"strconv" "strconv"
@ -42,6 +45,7 @@ func main() {
conf.GetConfig().PermissionConnectorAdminPort = o.GetIntDefault("PERMISSION_CONNECTOR_ADMIN_PORT", 4467) conf.GetConfig().PermissionConnectorAdminPort = o.GetIntDefault("PERMISSION_CONNECTOR_ADMIN_PORT", 4467)
// config LDAP // config LDAP
conf.GetConfig().SourceMode = o.GetStringDefault("SOURCE_MODE", "ldap")
conf.GetConfig().LDAPEndpoints = o.GetStringDefault("LDAP_ENDPOINTS", "ldap:389") conf.GetConfig().LDAPEndpoints = o.GetStringDefault("LDAP_ENDPOINTS", "ldap:389")
conf.GetConfig().LDAPBindDN = o.GetStringDefault("LDAP_BINDDN", "cn=admin,dc=example,dc=com") conf.GetConfig().LDAPBindDN = o.GetStringDefault("LDAP_BINDDN", "cn=admin,dc=example,dc=com")
conf.GetConfig().LDAPBindPW = o.GetStringDefault("LDAP_BINDPW", "password") conf.GetConfig().LDAPBindPW = o.GetStringDefault("LDAP_BINDPW", "password")
@ -51,10 +55,36 @@ func main() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
generateRole()
discovery() discovery()
beego.Run() beego.Run()
} }
func generateRole() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
// if from ldap, create roles from ldap
if conf.GetConfig().SourceMode == "ldap" {
ldap := auth_connectors.New()
roles, err := ldap.GetRoles(context.Background())
if err != nil {
panic(err)
}
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)
}
}
}
}
}
func generateSelfPeer() error { func generateSelfPeer() error {
// TODO check if files at private & public path are set // TODO check if files at private & public path are set
// check if files at private & public path are set // check if files at private & public path are set
@ -65,7 +95,7 @@ func generateSelfPeer() error {
return errors.New("public key path does not exist") return errors.New("public key path does not exist")
} }
// check if peer already exists // check if peer already exists
p := oclib.Search(nil, strconv.Itoa(peer.SELF.EnumIndex()), oclib.LibDataEnum(oclib.PEER)) p := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).Search(nil, strconv.Itoa(peer.SELF.EnumIndex()), false)
file := "" file := ""
f, err := os.ReadFile(conf.GetConfig().PublicKeyPath) f, err := os.ReadFile(conf.GetConfig().PublicKeyPath)
if err != nil { if err != nil {
@ -90,7 +120,7 @@ func generateSelfPeer() error {
PublicKey: file, PublicKey: file,
State: peer.SELF, State: peer.SELF,
} }
data := oclib.StoreOne(oclib.LibDataEnum(oclib.PEER), peer.Serialize()) data := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).StoreOne(peer.Serialize(peer))
if data.Err != "" { if data.Err != "" {
return errors.New(data.Err) return errors.New(data.Err)
} }
@ -99,7 +129,7 @@ func generateSelfPeer() error {
func discovery() { func discovery() {
api := tools.API{} api := tools.API{}
conn := infrastructure.GetPermissionConnector() conn := infrastructure.GetPermissionConnector("")
conn.CreateRole(conf.GetConfig().AdminRole) conn.CreateRole(conf.GetConfig().AdminRole)
conn.BindRole(conf.GetConfig().AdminRole, "admin") conn.BindRole(conf.GetConfig().AdminRole, "admin")

BIN
oc-auth

Binary file not shown.

View File

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

View File

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

View File

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