Commit ec271433 authored by Alexis POYEN's avatar Alexis POYEN
Browse files

WIP : manage OAuth authent with local user bind with app user

TODO: create app user if it doesn't exist yet
parent b8dc1b96
Pipeline #4757 failed with stages
in 1 minute and 8 seconds
HOSTNAME=sdk-go.127.0.0.1.nip.io
ADMIN_ROLE=ADMINS
ADMIN_GROUP=ADMINS
CLIENT_GROUP=CLIENTS
# Needed to user OAuth2 authentication :
REDIRECT_URL=https://${HOSTNAME}/OAuth2Callback
......
......@@ -21,7 +21,8 @@
"TOKEN_URL": "http://localhost:8090/token",
"USERINFO_URL": "http://localhost:8090/admininfo",
"LOGOUT_URL": "/",
"ADMIN_ROLE": "ADMINS",
"ADMIN_GROUP": "ADMINS",
"CLIENT_GROUP": "CLIENTS",
"HOSTNAME": "sdk-go.127.0.0.1.nip.io"
},
"args": ["-debug", "-https_port=1443"],
......@@ -44,7 +45,8 @@
"TOKEN_URL": "https://connexion-rec.grandlyon.fr/IdPOAuth2/token/oidc-rec",
"USERINFO_URL": "https://connexion-rec.grandlyon.fr/IdPOAuth2/userinfo/oidc-rec",
"LOGOUT_URL": "https://connexion-rec.grandlyon.fr/auth/logout.jsp",
"ADMIN_ROLE": "GGD_ORG_DG-DEES-DINSI-DAAG_TOUS",
"ADMIN_GROUP": "GGD_ORG_DG-DEES-DINSI-DAAG_TOUS",
"CLIENT_GROUP": "GGD_ORG_DG-DEES-DINSI-DAAG_TOUS",
"HOSTNAME": "vestibule.127.0.0.1.nip.io",
"ONLYOFFICE_TITLE": "VestibuleOffice",
"ONLYOFFICE_SERVER": "https://localhost:2443"
......
[
{
"id": "3",
"login": "admin",
"memberOf": [
"ADMINS"
],
"passwordHash": "$2a$10$w6aIsC8lfMSB9tXIDRgk9OztQS.4gBQA9Uoi0X7mCzz5mlTRIx4tq"
},
{
"id": "1",
"id": 1,
"idOAuth": "",
"login": "Dupond",
"memberOf": [
"USERS"
],
"role": "CLIENT",
"passwordHash": "$2a$10$PgiAoLxZhgNtr7kRK/DH5ezwT./7vRkWqFNEtJD1670z3Zf60HqgG"
},
{
"id": "2",
"id": 2,
"idOAuth": "",
"login": "Bakery",
"memberOf": [
"USERS"
],
"role": "CLIENT",
"passwordHash": "$2a$10$PgiAoLxZhgNtr7kRK/DH5ezwT./7vRkWqFNEtJD1670z3Zf60HqgG"
},
{
"id": 3,
"idOAuth": "",
"login": "banker",
"role": "BANKER",
"passwordHash": "$2a$10$w6aIsC8lfMSB9tXIDRgk9OztQS.4gBQA9Uoi0X7mCzz5mlTRIx4tq"
},
{
"id": 4,
"idOAuth": "",
"login": "admin",
"role": "ADMINS",
"passwordHash": "$2a$10$PgiAoLxZhgNtr7kRK/DH5ezwT./7vRkWqFNEtJD1670z3Zf60HqgG"
},
{
"id": 5,
"idOAuth": "1",
"login": "ADMIN",
"displayName": "Ad MIN",
"role": "ADMINS"
},
{
"id": 6,
"idOAuth": "",
"login": "banker2",
"role": "BANKER",
"passwordHash": "$2a$10$w6aIsC8lfMSB9tXIDRgk9OztQS.4gBQA9Uoi0X7mCzz5mlTRIx4tq"
}
]
\ No newline at end of file
package models
import (
"encoding/json"
"net/http"
"strconv"
"strings"
"forge.grandlyon.com/apoyen/sdk-go/pkg/auth"
)
func (d *DataHandler) HandleBankAccounts(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/BankAccounts/"))
switch method := r.Method; method {
case "GET":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o BankAccount
if err := d.db.Preload("Operations").First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
// Check that the bank account belong to a one of the banker's client
var userClient UserClient
if err := d.db.Where("id = ? and user_banker_id = ?", o.UserClientID, user.ID).First(&userClient).Error; err != nil {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []BankAccount
d.db.Preload("Operations").Where("user_client_id IN (?)", d.db.Table("user_clients").Select("id").Where("user_banker_id = ?", user.ID).QueryExpr()).Find(&o)
json.NewEncoder(w).Encode(o)
}
case UserClient:
if id != 0 {
var o BankAccount
if err := d.db.Preload("Operations").Where("id = ? AND user_client_id = ?", id, user.ID).First(&o).Error; err != nil {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []BankAccount
d.db.Preload("Operations").Where("user_client_id = ?", user.ID).Find(&o)
json.NewEncoder(w).Encode(o)
}
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
case "POST":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
var o BankAccount
err := json.NewDecoder(r.Body).Decode(&o)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
if o.UserClientID != 0 {
var userClient UserClient
if err := d.db.Where("id = ? and user_banker_id = ?", o.UserClientID, user.ID).First(&userClient).Error; err != nil {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
d.db.Create(&o)
} else {
http.Error(w, "id of UserClient is missing", http.StatusNotFound)
}
case UserClient:
http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed)
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
case "DELETE":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o BankAccount
if err := d.db.First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
if o.UserClientID != 0 {
var userClient UserClient
if err := d.db.Where("id = ? and user_banker_id = ?", o.UserClientID, user.ID).First(&userClient).Error; err != nil {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
d.db.Delete(&o)
} else {
http.Error(w, "id of UserClient is missing", http.StatusNotFound)
}
} else {
http.Error(w, "id is missing", http.StatusNotFound)
}
case UserClient:
http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed)
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
default:
http.Error(w, "method not allowed", 400)
}
}
package models
import (
"encoding/json"
"net/http"
"os"
"strconv"
"strings"
"forge.grandlyon.com/apoyen/sdk-go/pkg/auth"
)
func (d *DataHandler) HandleBankers(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/UserClients/"))
switch method := r.Method; method {
case "GET":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o UserBanker
if err := d.db.Preload("UserClients").Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []UserBanker
d.db.Preload("UserClients").Find(&o)
json.NewEncoder(w).Encode(o)
}
case UserClient:
if id != 0 && int(user.ID) == id {
var userClient UserClient
if err := d.db.Where("user_id = ?", user.ID).First(&userClient).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
var o UserBanker
if err := d.db.Where("id = ?", userClient.UserBankerID).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
}
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
case "POST":
if !auth.IsAllowed(w, r, []string{os.Getenv("ADMIN_ROLE")}) {
return
}
var o UserBanker
err := json.NewDecoder(r.Body).Decode(&o)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
d.db.Create(&o)
case "DELETE":
if !auth.IsAllowed(w, r, []string{os.Getenv("ADMIN_ROLE")}) {
return
}
if id != 0 {
var o UserClient
d.db.Delete(&o)
} else {
http.Error(w, "id is missing", http.StatusNotFound)
}
default:
http.Error(w, "method not allowed", 400)
}
}
// Add a Banker in DB
func (d *DataHandler) AddBanker(userBanker UserBanker) {
d.db.Create(&userBanker)
}
package models
import (
"encoding/json"
"net/http"
"strconv"
"strings"
"forge.grandlyon.com/apoyen/sdk-go/pkg/auth"
)
// HandleClients expose the UserClients API
func (d *DataHandler) HandleClients(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/UserClients/"))
switch method := r.Method; method {
case "GET":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o UserClient
if err := d.db.Preload("BankAccounts").Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
if o.UserBankerID != user.ID {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []UserClient
d.db.Preload("BankAccounts").Find(&o)
json.NewEncoder(w).Encode(o)
}
case UserClient:
if id != 0 && int(user.ID) == id {
var o UserClient
if err := d.db.Preload("BankAccounts").Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else if id == 0 {
var o []UserClient
d.db.Preload("BankAccounts").Where("id = ?", user.ID).Find(&o)
json.NewEncoder(w).Encode(o)
} else {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
case "POST":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
var o UserClient
err := json.NewDecoder(r.Body).Decode(&o)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
o.UserBankerID = user.ID
d.db.Create(&o)
case UserClient:
http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed)
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
case "DELETE":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o UserClient
if err := d.db.Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
if o.UserBankerID != user.ID {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
// Delete bank accounts of user
d.db.Where("user_client_id = ?", o.ID).Delete(&BankAccount{})
d.db.Delete(&o)
} else {
http.Error(w, "id is missing", http.StatusNotFound)
}
case UserClient:
http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed)
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
default:
http.Error(w, "method not allowed", 400)
}
}
// Add a Client in DB
func (d *DataHandler) AddClient(userClient UserClient) {
d.db.Create(&userClient)
}
package models
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"time"
......@@ -25,7 +21,7 @@ type DataHandler struct {
}
// NewDataHandler init a DataHandler and returns a pointer to it
func NewDataHandler(authzFromMain authzFunc) *DataHandler {
func NewDataHandler() *DataHandler {
db, err := gorm.Open("sqlite3", "./data/test.db")
if err != nil {
panic("failed to connect database")
......@@ -64,8 +60,7 @@ type UserClient struct {
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
UserID string
AuthType string
UserID int
Name string
UserBankerID uint
BankAccounts []BankAccount
......@@ -77,8 +72,7 @@ type UserBanker struct {
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
UserID string
AuthType string
UserID int
Name string
UserClients []UserClient
}
......@@ -108,426 +102,28 @@ type Operation struct {
Creditor uint
}
// HandleClients expose the UserClients API
func (d *DataHandler) HandleClients(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/UserClients/"))
switch method := r.Method; method {
case "GET":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o UserClient
if err := d.db.Preload("BankAccounts").Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
if o.UserBankerID != user.ID {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []UserClient
d.db.Preload("BankAccounts").Find(&o)
json.NewEncoder(w).Encode(o)
}
case UserClient:
if id != 0 && int(user.ID) == id {
var o UserClient
if err := d.db.Preload("BankAccounts").Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else if id == 0 {
var o []UserClient
d.db.Preload("BankAccounts").Where("id = ?", user.ID).Find(&o)
json.NewEncoder(w).Encode(o)
} else {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
case "POST":
if !auth.IsAllowed(w, r, []string{os.Getenv("ADMIN_ROLE")}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
var o UserClient
err := json.NewDecoder(r.Body).Decode(&o)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
o.UserBankerID = user.ID
d.db.Create(&o)
case UserClient:
http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed)
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
case "DELETE":
if !auth.IsAllowed(w, r, []string{os.Getenv("ADMIN_ROLE")}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o UserClient
if err := d.db.Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
if o.UserBankerID != user.ID {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
return
}
// Delete bank accounts of user
d.db.Where("user_client_id = ?", o.ID).Delete(&BankAccount{})
d.db.Delete(&o)
} else {
http.Error(w, "id is missing", http.StatusNotFound)
}
case UserClient:
http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed)
default:
http.Error(w, "Could not get logged user", http.StatusInternalServerError)
}
default:
http.Error(w, "method not allowed", 400)
}
}
func (d *DataHandler) HandleBankers(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/UserClients/"))
switch method := r.Method; method {
case "GET":
if !auth.IsAllowed(w, r, []string{"*"}) {
return
}
user := d.getLoggedUser(w, r)
switch user := user.(type) {
case UserBanker:
if id != 0 {
var o UserBanker
if err := d.db.Preload("UserClients").Where("id = ?", id).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []UserBanker
d.db.Preload("UserClients").Find(&o)
json.NewEncoder(w).Encode(o)
}
case UserClient:
if id != 0 && int(user.ID) == id {
var userClient UserClient
if err := d.db.Where("user_id = ? AND auth_type = ?", user.ID, user.AuthType).First(&userClient).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
var o UserBanker
if err := d.db.Where("id = ?", userClient.UserBankerID).First(&o).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else {
http.Error(w, "You can not access this ressource", http.StatusForbidden)
}