Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Changes for v12 and Nginx #2

Merged
merged 4 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This initialization can be handled by the `reset.sql` script.

- `LOG_LEVEL`(optional): defines the minimum level that should be [logged](https://github.com/eliona-smart-building-assistant/go-utils/blob/main/log/README.md). The default level is `info`.

- `SSO_SERVER_PORT` (optional): defines the port for Single Sign On Services, here SAML 2.0. The default value is Port `8080`.
- `SSO_SERVER_PORT` (optional): defines the port for Single Sign On Services, here SAML 2.0. The default value is Port `80`.

### Database tables ###

Expand Down
66 changes: 17 additions & 49 deletions apiservices/api_configuration_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ package apiservices

import (
"context"
"errors"
"net/http"
"saml-sso/apiserver"
"saml-sso/conf"
)

// ConfigurationApiService is a service that implements the logic for the ConfigurationAPIServicer
Expand All @@ -35,88 +35,56 @@ func NewConfigurationApiService() apiserver.ConfigurationAPIServicer {

// GetAdvancedConfiguration - Get Advanced Configuration
func (s *ConfigurationApiService) GetAdvancedConfiguration(ctx context.Context) (apiserver.ImplResponse, error) {
// TODO - update GetAdvancedConfiguration with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
advCnf, err := conf.GetAdvancedConfig(ctx)

//TODO: Uncomment the next line to return response Response(200, AdvancedConfiguration{}) or use other options such as http.Ok ...
//return Response(200, AdvancedConfiguration{}), nil

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("GetAdvancedConfiguration method not implemented")
return apiserver.Response(http.StatusOK, advCnf), err
zdevaty marked this conversation as resolved.
Show resolved Hide resolved
}

// GetAttributeMapping - Get Attribute Mapping
func (s *ConfigurationApiService) GetAttributeMapping(ctx context.Context) (apiserver.ImplResponse, error) {
// TODO - update GetAttributeMapping with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.

//TODO: Uncomment the next line to return response Response(200, AttributeMap{}) or use other options such as http.Ok ...
//return Response(200, AttributeMap{}), nil
attrMap, err := conf.GetAttributeMapping(ctx)

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("GetAttributeMapping method not implemented")
return apiserver.Response(http.StatusOK, attrMap), err
}

// GetBasicConfiguration - Get Basic Configurations
func (s *ConfigurationApiService) GetBasicConfiguration(ctx context.Context) (apiserver.ImplResponse, error) {
// TODO - update GetBasicConfiguration with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
basicCnf, err := conf.GetBasicConfig(ctx)

//TODO: Uncomment the next line to return response Response(200, BasicConfiguration{}) or use other options such as http.Ok ...
//return Response(200, BasicConfiguration{}), nil

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("GetBasicConfiguration method not implemented")
return apiserver.Response(http.StatusOK, basicCnf), err
}

// GetPermissionMapping - Get Permission Mapping
func (s *ConfigurationApiService) GetPermissionMapping(ctx context.Context) (apiserver.ImplResponse, error) {
// TODO - update GetPermissionMapping with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.

//TODO: Uncomment the next line to return response Response(200, Permissions{}) or use other options such as http.Ok ...
//return Response(200, Permissions{}), nil
permMap, err := conf.GetPermissionSettings(ctx)

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("GetPermissionMapping method not implemented")
return apiserver.Response(http.StatusOK, permMap), err
}

// PutAdvancedConfiguration - Creates or Update Advanced Configuration
func (s *ConfigurationApiService) PutAdvancedConfiguration(ctx context.Context, advancedConfiguration apiserver.AdvancedConfiguration) (apiserver.ImplResponse, error) {
// TODO - update PutAdvancedConfiguration with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
cnfRet, err := conf.SetAdvancedConfig(ctx, &advancedConfiguration)

//TODO: Uncomment the next line to return response Response(200, AdvancedConfiguration{}) or use other options such as http.Ok ...
//return Response(200, AdvancedConfiguration{}), nil

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("PutAdvancedConfiguration method not implemented")
return apiserver.Response(http.StatusOK, cnfRet), err
}

// PutAttributeMapping - Creates or Update Attribute Mapping
func (s *ConfigurationApiService) PutAttributeMapping(ctx context.Context, attributeMap apiserver.AttributeMap) (apiserver.ImplResponse, error) {
// TODO - update PutAttributeMapping with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.

//TODO: Uncomment the next line to return response Response(200, AttributeMap{}) or use other options such as http.Ok ...
//return Response(200, AttributeMap{}), nil
mapRet, err := conf.SetAttributeMapping(ctx, &attributeMap)

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("PutAttributeMapping method not implemented")
return apiserver.Response(http.StatusOK, mapRet), err
}

// PutBasicConfiguration - Creates or Update Basic Configuration
func (s *ConfigurationApiService) PutBasicConfiguration(ctx context.Context, basicConfiguration apiserver.BasicConfiguration) (apiserver.ImplResponse, error) {
// TODO - update PutBasicConfiguration with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
cnfRet, err := conf.SetBasicConfig(ctx, &basicConfiguration)

//TODO: Uncomment the next line to return response Response(200, BasicConfiguration{}) or use other options such as http.Ok ...
//return Response(200, BasicConfiguration{}), nil

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("PutBasicConfiguration method not implemented")
return apiserver.Response(http.StatusOK, cnfRet), err
}

// PutPermissionMapping - Creates or Update Permission Mapping Configurations
func (s *ConfigurationApiService) PutPermissionMapping(ctx context.Context, permissions apiserver.Permissions) (apiserver.ImplResponse, error) {
// TODO - update PutPermissionMapping with the required logic for this service method.
// Add api_configuration_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.

//TODO: Uncomment the next line to return response Response(200, Permissions{}) or use other options such as http.Ok ...
//return Response(200, Permissions{}), nil
permRet, err := conf.SetPermissionSettings(ctx, &permissions)

return apiserver.Response(http.StatusNotImplemented, nil), errors.New("PutPermissionMapping method not implemented")
return apiserver.Response(http.StatusOK, permRet), err
}
83 changes: 83 additions & 0 deletions apiservices/api_configuration_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// This file is part of the eliona project.
// Copyright © 2023 Eliona by IoTEC AG. All Rights Reserved.
// ______ _ _
// | ____| (_)
// | |__ | |_ ___ _ __ __ _
// | __| | | |/ _ \| '_ \ / _` |
// | |____| | | (_) | | | | (_| |
// |______|_|_|\___/|_| |_|\__,_|
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package apiservices_test

import (
"context"
"database/sql"
"fmt"
"saml-sso/apiservices"
"saml-sso/conf"
"testing"

"github.com/eliona-smart-building-assistant/go-eliona/app"
"github.com/eliona-smart-building-assistant/go-utils/db"
)

func TestApp_AppApi_Configuration_InitDB(t *testing.T) {
err := conf.UserLeicomInit()
if err != nil {
t.Log("user leicom, ", err)
}
err = conf.DropOwnSchema()
if err != nil {
// no error, if schema not exist
t.Log("drop schema, ", err)
}

execFunc := app.ExecSqlFile("../conf/init.sql")
err = execFunc(db.NewConnection())
if err != nil {
t.Error("init.sql failed, ", err)
}
}

func TestApp_AppApi_Configuration_GetBasicConfig(t *testing.T) {
apiService := apiservices.NewConfigurationApiService()
cnf, err := apiService.GetBasicConfiguration(context.Background())
if err != sql.ErrNoRows {
t.Error(err)
}
fmt.Println(cnf)
}

func TestApp_AppApi_Configuration_GetAdvancedConfig(t *testing.T) {

}

func TestApp_AppApi_Configuration_GetAttributeMapping(t *testing.T) {

}

func TestApp_AppApi_Configuration_GetPermissionMap(t *testing.T) {

}

func TestApp_AppApi_Configuration_PutBasicConfig(t *testing.T) {

}

func TestApp_AppApi_Configuration_PutAdvancedConfig(t *testing.T) {

}

func TestApp_AppApi_Configuration_PutAttributeMapping(t *testing.T) {

}

func TestApp_AppApi_Configuration_PutPermissionMap(t *testing.T) {

}
11 changes: 8 additions & 3 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package main

import (
"context"
"fmt"
"io"
"net/http"
"saml-sso/apiserver"
Expand All @@ -34,7 +33,7 @@ import (
const (
LOG_REGIO = "app"
API_SERVER_PORT = 3000
SSO_SERVER_PORT = 8081 // Publicly accessible. See wiki.
SSO_SERVER_PORT = 80 // Publicly accessible without auth. See wiki.

SAML_SPECIFIC_ENDPOINT_PATH = "/saml/"
)
Expand Down Expand Up @@ -83,7 +82,8 @@ func run() {
apiPort := common.Getenv("API_SERVER_PORT", strconv.Itoa(API_SERVER_PORT))
samlSpPort := common.Getenv("SSO_SERVER_PORT", strconv.Itoa(SSO_SERVER_PORT))

fmt.Println(basicConfig.OwnUrl + ":" + apiPort)
log.Debug(LOG_REGIO, "own url: %v, api port: %v", basicConfig.OwnUrl, apiPort)

sp, err := saml.NewServiceProviderAdvanced(
basicConfig.ServiceProviderCertificate,
basicConfig.ServiceProviderPrivateKey,
Expand Down Expand Up @@ -129,6 +129,11 @@ func run() {
sp.GetMiddleWare().RequireAccount(authHandleFunc))
http.Handle(SAML_SPECIFIC_ENDPOINT_PATH, sp.GetMiddleWare())

// for backwards compatibility, can be removed when the frontend is reworked to the new generic /sso/* endpoints
http.Handle("/adfs/active/", activeHandleFunc)
http.Handle("/adfs/auth/",
sp.GetMiddleWare().RequireAccount(authHandleFunc))

log.Info(LOG_REGIO, "started @ %v", samlSpPort)
err = http.ListenAndServe(":"+samlSpPort, nil)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions conf/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ CREATE TABLE IF NOT EXISTS saml_sp.advanced_config (

CREATE TABLE IF NOT EXISTS saml_sp.permissions (
id INT PRIMARY KEY NOT NULL DEFAULT 1 REFERENCES saml_sp.basic_config(id) ON UPDATE CASCADE,
default_system_role TEXT NOT NULL DEFAULT 'regular' , -- reference to is maybe a bad idea (due to the new ACL)
default_proj_role TEXT NOT NULL DEFAULT 'operator' ,
default_system_role TEXT NOT NULL DEFAULT 'System user' , -- reference to is maybe a bad idea (due to the new ACL)
default_proj_role TEXT NOT NULL DEFAULT 'Project user' ,
system_role_saml_attribute TEXT ,
system_role_map JSON ,
proj_role_saml_attribute TEXT ,
Expand Down
44 changes: 43 additions & 1 deletion eliona/others.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ const (
"JOIN public.eliona_secret " +
"USING (schema), public.claim_jwt(role, now() + validity,user_id,null) jwt " +
"WHERE lower(u.email) = lower($1) AND NOT u.archived)"

OTHERS_GET_JWT_QUERY_V12 = "(SELECT public.make_jwt(jwt,secret) " +
"FROM public.eliona_user u " +
"JOIN public.acl_role r ON (u.role_id = r.role_id) " +
"JOIN public.project_user USING (user_id) " +
"JOIN public.eliona_secret USING (schema), " +
"public.claim_jwt(role, now() + validity,user_id,proj_id,r.role_id::text,schema) jwt " +
"WHERE lower(u.email) = lower($1) AND NOT u.archived)"
)

func GetElionaJsonWebToken(email string) (*string, error) {
Expand Down Expand Up @@ -70,9 +78,13 @@ func GetElionaJsonWebToken(email string) (*string, error) {
if strings.Contains(version, "v10.") {
log.Debug(LOG_REGIO, "eliona v10")
jwtQuery = OTHERS_GET_JWT_QUERY_V10
} else if strings.Contains(version, "v11.") &&
!strings.Contains(version, "v11.1.5") {
log.Debug(LOG_REGIO, "eliona v11")
jwtQuery = OTHERS_GET_JWT_QUERY_V11
} else {
// assume, that the version is newer (with ACL)
jwtQuery = OTHERS_GET_JWT_QUERY_V11
jwtQuery = OTHERS_GET_JWT_QUERY_V12
}

row = db.QueryRow(jwtQuery, email)
Expand All @@ -96,6 +108,36 @@ func UpdateElionaUserArchivedPhone(email string, phone *string, archived bool) e
return err
}

func GetFirstProjectId() (projectId string, err error) {
row := getDb().QueryRow("SELECT proj_id FROM eliona_project ORDER BY proj_id LIMIT 1")

if err = row.Err(); err != nil {
return
}

err = row.Scan(&projectId)
return
}

func GetRoleIdByDisplayName(displayName string) (roleId int, err error) {
row := getDb().QueryRow("SELECT role_id FROM acl_role WHERE displayname = $1", displayName)

if err = row.Err(); err != nil {
return
}

err = row.Scan(&roleId)
return
}

func SetProjectUser(projectId string, userId *string, roleId int) (err error) {

_, err = getDb().Exec("INSERT INTO project_user (proj_id, user_id, role_id) "+
"VALUES ($1, $2, $3)", projectId, userId, roleId)

return
}

func getDb() *sql.DB {
return db.Database(app.AppName())
}
11 changes: 11 additions & 0 deletions eliona/others_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,24 @@
package eliona_test

import (
"os"
"saml-sso/eliona"
"testing"

"github.com/eliona-smart-building-assistant/go-utils/log"
)

func TestApp_Others(t *testing.T) {

// this test needs a real eliona db to due missing tables
// in the test db
_, realDb := os.LookupEnv("REAL_DB")
if !realDb {
log.Warn("TestApp_Others", "test disabled because missing env var REAL_DB")
t.Log("TestApp_Others: test disabled because missing env var REAL_DB")
return
}

token, err := eliona.GetElionaJsonWebToken("su#@eliona.io")
if err != nil {
t.Error(err)
Expand Down
Loading
Loading