Skip to content

Commit

Permalink
Issue #434, Refactored with shared pkg for sessionSupport and oidcSup…
Browse files Browse the repository at this point in the history
…port. Issue #440, Enable TLS on Hexa Admin server

Signed-off-by: Phil Hunt <[email protected]>
  • Loading branch information
independentid committed Jul 18, 2024
1 parent 8535e3e commit 8804885
Show file tree
Hide file tree
Showing 19 changed files with 220 additions and 70 deletions.
37 changes: 25 additions & 12 deletions demo/.env_development
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
export OVERMIND_NO_PORT=1
export OPA_SERVER_URL=http://opa-agent:8887/v1/data/authz/allow
export ORCHESTRATOR_URL=http://0.0.0.0:8885
OVERMIND_NO_PORT=1
OPA_SERVER_URL=http://opa-agent:8887/v1/data/authz/allow

export ORCHESTRATOR_HOSTPORT=0.0.0.0:8885
export HEXA_DEMO_URL=http://0.0.0.0:8886
export HEXA_DEMO_CONFIG_URL=http://0.0.0.0:8889
export ORCHESTRATOR_CONFIG_FILE=./deployments/hexaOrchestrator/config/config.json
export POSTGRES_DB=keycloak_db
export POSTGRES_USER=keycloak_db_user
export POSTGRES_PASSWORD=keycload_db_password_4_now
export KEYCLOAK_ADMIN=admin
export KEYCLOAK_ADMIN_PASSWORD=not4u2no
ORCHESTRATOR_URL=https://hexa-orchestrator:8885

HEXA_CA_CERT=/Users/pjdhunt/git/policy-orchestrator/demo/.certs/ca-cert.pem
HEXA_JWT_AUTH_ENABLE=true
HEXA_JWT_REALM=Hexa-Orchestrator-Realm
HEXA_OAUTH_CLIENT_ID=hexaclient
HEXA_OAUTH_CLIENT_SECRET=uuXVzfbqH635Ob0oTON1uboONUqasmTt
HEXA_OAUTH_TOKEN_ENDPOINT=http://127.0.0.1:8080/realms/Hexa-Orchestrator-Realm/protocol/openid-connect/token
HEXA_OIDC_CLIENT_ID=hexaclient
HEXA_OIDC_CLIENT_SECRET=uuXVzfbqH635Ob0oTON1uboONUqasmTt
HEXA_OIDC_ENABLED=true
HEXA_OIDC_PROVIDER_URL=http://localhost:8080/realms/Hexa-Orchestrator-Realm
OPA_SERVER_URL=http://opa-agent:8887/v1/data/authz/allow
ORCHESTRATOR_URL=https://hexa-orchestrator:8885
ORCHESTRATOR_HOSTPORT=0.0.0.0:8885
HEXA_DEMO_URL=http://0.0.0.0:8886
HEXA_DEMO_CONFIG_URL=http://0.0.0.0:8889
ORCHESTRATOR_CONFIG_FILE=./deployments/hexaOrchestrator/config/config.json
POSTGRES_DB=keycloak_db
POSTGRES_USER=keycloak_db_user
POSTGRES_PASSWORD=keycload_db_password_4_now
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=not4u2no
21 changes: 19 additions & 2 deletions demo/cmd/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"net/http"
"os"

"github.com/hexa-org/policy-mapper/pkg/keysupport"
"github.com/hexa-org/policy-mapper/pkg/sessionSupport"
"github.com/hexa-org/policy-orchestrator/demo/pkg/hexaConstants"
log "golang.org/x/exp/slog"

Expand All @@ -17,7 +19,10 @@ import (
func App(addr string, orchestratorUrl string) *http.Server {

client := admin.NewOrchestratorClient(nil, orchestratorUrl)
handlers := admin.LoadHandlers(orchestratorUrl, client)

sessionHandler := sessionSupport.NewSessionManager()

handlers := admin.LoadHandlers(orchestratorUrl, client, sessionHandler)
return websupport.Create(addr, handlers, websupport.Options{})
}

Expand All @@ -31,7 +36,19 @@ func newApp(addr string) (*http.Server, net.Listener) {
orchestratorUrl := os.Getenv("ORCHESTRATOR_URL")

listener, _ := net.Listen("tcp", addr)
return App(listener.Addr().String(), orchestratorUrl), listener
server := App(listener.Addr().String(), orchestratorUrl)

if websupport.IsTlsEnabled() {
keyConfig := keysupport.GetKeyConfig()
err := keyConfig.InitializeKeys()
if err != nil {
log.Error("Error initializing keys: " + err.Error())
panic(err)
}

websupport.WithTransportLayerSecurity(keyConfig.ServerCertPath, keyConfig.ServerKeyPath, server)
}
return server, listener
}

func main() {
Expand Down
25 changes: 23 additions & 2 deletions demo/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
HEXA_CERT_DIRECTORY: "/home/certs"
HEXA_SERVER_CERT: "/home/certs/server-hexaorchestrator-cert.pem"
HEXA_SERVER_KEY_PATH: "/home/certs/server-hexaorchestrator-key.pem"
HEXA_SERVER_DNS_NAME: "hexa-orchestrator"
HEXA_SERVER_DNS_NAME: "hexa-orchestrator,localhost"
HEXA_JWT_REALM: Hexa-Orchestrator-Realm
HEXA_TOKEN_JWKSURL: http://keycloak:8080/realms/Hexa-Orchestrator-Realm/protocol/openid-connect/certs
HEXA_JWT_AUTH_ENABLE: true
Expand All @@ -41,7 +41,13 @@ services:
- hexa_network
environment:
ORCHESTRATOR_URL: https://hexa-orchestrator:8885
# HEXA_CA_CERT used to install the self-signed CA trust root to call Orchestrator service
HEXA_CA_CERT: "/home/certs/ca-cert.pem"
HEXA_TLS_ENABLED: false
HEXA_CERT_DIRECTORY: "/home/certs"
HEXA_SERVER_CERT: "/home/certs/server-hexa-admin-cert.pem"
HEXA_SERVER_KEY_PATH: "/home/certs/server-hexa-admin-key.pem"
HEXA_SERVER_DNS_NAME: "admin.hexa.org,localhost"
HEXA_JWT_REALM: Hexa-Orchestrator-Realm
HEXA_JWT_AUTH_ENABLE: true
HEXA_OAUTH_CLIENT_ID: hexaclient
Expand All @@ -59,6 +65,7 @@ services:
hexa-industry-demo-app:
image: independentid/hexaopa:latest
container_name: hexa-demo
hostname: demo.hexa.org
ports:
- "8886:8886"
command: /app/hexaIndustriesDemo
Expand All @@ -69,8 +76,22 @@ services:
environment:
PORT: 8886
OPA_SERVER_URL: https://hexa-opa-server:8887/v1/data/hexaPolicy
HEXAOPA_DETAIL: "notes&pretty"
# HEXAOPA_DETAIL enables debug responses in console notes, fails, full, debug
HEXAOPA_DETAIL: "notes"
# HEXA_CA_CERT is used to trust self-signed TLS keys for hexa-opa-sidecar (OPA_SERVER_URL)
HEXA_CA_CERT: "/home/certs/ca-cert.pem"
HEXA_CERT_DIRECTORY: "/home/certs"
HEXA_OIDC_ENABLED: true
HEXA_OIDC_CLIENT_ID: hexaclient
HEXA_OIDC_CLIENT_SECRET: "uuXVzfbqH635Ob0oTON1uboONUqasmTt"
HEXA_OIDC_PROVIDER_URL: "http://keycloak:8080/realms/Hexa-Orchestrator-Realm"
# If TLS enabled, OIDC redirect must be changed to https
HEXA_OIDC_REDIRECT_URL: "http://demo.hexa.org:8886/redirect"
HEXA_TLS_ENABLED: false
# Following only used when HEXA_TLS_ENABLED=true and auto generate keys enabled (default)
HEXA_SERVER_CERT: "/home/certs/server-hexademo-cert.pem"
HEXA_SERVER_KEY_PATH: "/home/certs/server-hexademo-key.pem"
HEXA_SERVER_DNS_NAME: "demo.hexa.org,localhost"
volumes:
- "./.certs:/home/certs:ro"

Expand Down
50 changes: 33 additions & 17 deletions demo/internal/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (

"github.com/gorilla/mux"
"github.com/hexa-org/policy-mapper/pkg/hexapolicy"
"github.com/hexa-org/policy-mapper/pkg/oidcSupport"
"github.com/hexa-org/policy-mapper/pkg/sessionSupport"
log "golang.org/x/exp/slog"
)

//go:embed resources
Expand All @@ -29,29 +32,42 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/integrations", http.StatusPermanentRedirect)
}

func LoadHandlers(orchestratorUrl string, client Client) func(router *mux.Router) {
apps := NewApplicationsHandler(orchestratorUrl, client)
integrations := NewIntegrationsHandler(orchestratorUrl, client)
orchestration := NewOrchestrationHandler(orchestratorUrl, client)
func LoadHandlers(orchestratorUrl string, client Client, sessionHandler sessionSupport.SessionManager) func(router *mux.Router) {

oidcHandler, err := oidcSupport.NewOidcClientHandler(sessionHandler, &resources)
apps := NewApplicationsHandler(sessionHandler, orchestratorUrl, client)

integrations := NewIntegrationsHandler(orchestratorUrl, client, sessionHandler)
orchestration := NewOrchestrationHandler(orchestratorUrl, client, sessionHandler)
status := NewStatusHandler(orchestratorUrl, client)

return func(router *mux.Router) {
router.HandleFunc("/", IndexHandler).Methods("GET")
router.HandleFunc("/integrations", integrations.List).Methods("GET")
router.HandleFunc("/integrations/new", integrations.New).Methods("GET").Queries("provider", "{provider}")
router.HandleFunc("/integrations", integrations.CreateIntegration).Methods("POST")
router.HandleFunc("/integrations/{id}", integrations.Delete).Methods("POST")
router.HandleFunc("/applications", apps.List).Methods("GET")
router.HandleFunc("/applications/{id}", apps.Show).Methods("GET")
router.HandleFunc("/applications/{id}/policies", apps.Policies).Methods("GET")
router.HandleFunc("/applications/{id}/edit", apps.Edit).Methods("GET")
router.HandleFunc("/applications/{id}", apps.Update).Methods("POST")
router.HandleFunc("/orchestration/new", orchestration.New).Methods("GET")
router.HandleFunc("/orchestration", orchestration.Update).Methods("POST")
router.HandleFunc("/status", status.StatusHandler).Methods("GET")

oidcHandler.InitHandlers(router)
if err != nil {
log.Error(err.Error())
log.Warn("OIDC Login is disabled")
}
if !oidcHandler.Enabled {
router.HandleFunc("/", IndexHandler)
}

router.HandleFunc("/integrations", oidcHandler.HandleSessionScope(integrations.List, []string{"integration"})).Methods("GET")
router.HandleFunc("/integrations/new", oidcHandler.HandleSessionScope(integrations.New, []string{"integration"})).Methods("GET").Queries("provider", "{provider}")
router.HandleFunc("/integrations", oidcHandler.HandleSessionScope(integrations.CreateIntegration, []string{"integration"})).Methods("POST")
router.HandleFunc("/integrations/{id}", oidcHandler.HandleSessionScope(integrations.Delete, []string{"integration"})).Methods("POST")
router.HandleFunc("/applications", oidcHandler.HandleSessionScope(apps.List, []string{"integration"})).Methods("GET")
router.HandleFunc("/applications/{id}", oidcHandler.HandleSessionScope(apps.Show, []string{"integration"})).Methods("GET")
router.HandleFunc("/applications/{id}/policies", oidcHandler.HandleSessionScope(apps.Policies, []string{"integration"})).Methods("GET")
router.HandleFunc("/applications/{id}/edit", oidcHandler.HandleSessionScope(apps.Edit, []string{"integration"})).Methods("GET")
router.HandleFunc("/applications/{id}", oidcHandler.HandleSessionScope(apps.Update, []string{"integration"})).Methods("POST")
router.HandleFunc("/orchestration/new", oidcHandler.HandleSessionScope(orchestration.New, []string{"integration"})).Methods("GET")
router.HandleFunc("/orchestration", oidcHandler.HandleSessionScope(orchestration.Update, []string{"integration"})).Methods("POST")
router.HandleFunc("/status", oidcHandler.HandleSessionScope(status.StatusHandler, []string{"integration"})).Methods("GET")

staticFs, _ := fs.Sub(resources, "resources/static")
fileServer := http.FileServer(http.FS(staticFs))
router.PathPrefix("/").Handler(http.StripPrefix("/", fileServer))
}

}
4 changes: 3 additions & 1 deletion demo/internal/admin/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"testing"

"github.com/hexa-org/policy-mapper/pkg/sessionSupport"
"github.com/hexa-org/policy-orchestrator/demo/internal/admin"
"github.com/hexa-org/policy-orchestrator/demo/internal/admin/test"

Expand All @@ -15,8 +16,9 @@ import (
)

func TestAdminHandlers(t *testing.T) {
sessionHandler := sessionSupport.NewSessionManager()
listener, _ := net.Listen("tcp", "localhost:0")
handlers := admin.LoadHandlers("localhost:8885", new(admin_test.MockClient))
handlers := admin.LoadHandlers("localhost:8885", new(admin_test.MockClient), sessionHandler)
server := websupport.Create(listener.Addr().String(), handlers, websupport.Options{})
go websupport.Start(server, listener)
healthsupport.WaitForHealthy(server)
Expand Down
27 changes: 21 additions & 6 deletions demo/internal/admin/applications.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"

"github.com/gorilla/mux"
"github.com/hexa-org/policy-mapper/pkg/sessionSupport"
"github.com/hexa-org/policy-mapper/pkg/websupport"
)

Expand All @@ -32,10 +33,11 @@ type ApplicationsHandler interface {
type appsHandler struct {
orchestratorUrl string
client Client
session sessionSupport.SessionManager
}

func NewApplicationsHandler(orchestratorUrl string, client Client) ApplicationsHandler {
return appsHandler{orchestratorUrl, client}
func NewApplicationsHandler(sessionHandler sessionSupport.SessionManager, orchestratorUrl string, client Client) ApplicationsHandler {
return appsHandler{orchestratorUrl, client, sessionHandler}
}

func (p appsHandler) List(w http.ResponseWriter, r *http.Request) {
Expand All @@ -51,7 +53,11 @@ func (p appsHandler) List(w http.ResponseWriter, r *http.Request) {
log.Println(clientErr)
return
}
model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "applications": foundApplications}}
sessionInfo, err := p.session.Session(r)
if err != nil {
sessionInfo = &sessionSupport.SessionInfo{}
}
model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "applications": foundApplications, "session": sessionInfo}}
_ = websupport.ModelAndView(w, &resources, "applications", model)
w.Header()
}
Expand Down Expand Up @@ -79,7 +85,11 @@ func (p appsHandler) Show(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
_ = json.Indent(&buffer, []byte(rawJson), "", " ")
resourceLink := fmt.Sprintf("/applications/%v", identifier)
model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "resource_link": resourceLink, "application": foundApplication, "policies": foundPolicies, "rawJson": buffer.String()}}
sessionInfo, err := p.session.Session(r)
if err != nil {
sessionInfo = &sessionSupport.SessionInfo{}
}
model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "resource_link": resourceLink, "application": foundApplication, "policies": foundPolicies, "rawJson": buffer.String(), "session": sessionInfo}}
_ = websupport.ModelAndView(w, &resources, "applications_show", model)
}

Expand All @@ -94,17 +104,22 @@ func (p appsHandler) Edit(w http.ResponseWriter, r *http.Request) {
return
}

sessionInfo, err := p.session.Session(r)
if err != nil {
sessionInfo = &sessionSupport.SessionInfo{}
}
foundPolicies, rawJson, policiesError := p.client.GetPolicies(identifier)
if policiesError != nil {
model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "application": foundApplication, "message": policiesError.Error()}}

model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "application": foundApplication, "message": policiesError.Error(), "session": sessionInfo}}
_ = websupport.ModelAndView(w, &resources, "applications_edit", model)
log.Println(policiesError)
return
}

var buffer bytes.Buffer
_ = json.Indent(&buffer, []byte(rawJson), "", " ")
model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "application": foundApplication, "policies": foundPolicies, "rawJson": buffer.String()}}
model := websupport.Model{Map: map[string]interface{}{"resource": "applications", "application": foundApplication, "policies": foundPolicies, "rawJson": buffer.String(), "session": sessionInfo}}
_ = websupport.ModelAndView(w, &resources, "applications_edit", model)
}

Expand Down
7 changes: 6 additions & 1 deletion demo/internal/admin/applications_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import (
"io"
"net"
"net/http"
"os"
"testing"

"github.com/hexa-org/policy-mapper/pkg/hexapolicy"
"github.com/hexa-org/policy-mapper/pkg/oidcSupport"
"github.com/hexa-org/policy-mapper/pkg/sessionSupport"
"github.com/hexa-org/policy-orchestrator/demo/internal/admin"
"github.com/hexa-org/policy-orchestrator/demo/internal/admin/test"

Expand All @@ -31,9 +34,11 @@ func TestApplications(t *testing.T) {
func (suite *ApplicationsSuite) SetupTest() {
listener, _ := net.Listen("tcp", "localhost:0")
suite.client = &admin_test.MockClient{Url: "http://noop"}
_ = os.Setenv(oidcSupport.EnvOidcEnabled, "false")
sessionHandler := sessionSupport.NewSessionManager()
suite.server = websupport.Create(
listener.Addr().String(),
admin.LoadHandlers("http://noop", suite.client),
admin.LoadHandlers("http://noop", suite.client, sessionHandler),
websupport.Options{})
go websupport.Start(suite.server, listener)
healthsupport.WaitForHealthy(suite.server)
Expand Down
Loading

0 comments on commit 8804885

Please sign in to comment.