diff --git a/Gopkg.lock b/Gopkg.lock index 649bfdf40..2f0293685 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -18,7 +18,8 @@ version = "2020.02.11" [[projects]] - digest = "1:f00a04c3f9923917a7b65d7f2e785a653f88cd9fca0e164abac4f369a4533a62" + branch = "ct-2375" + digest = "1:4473c7f7e18551f287ad6334244f23102629d28a07d2cc9d732bc6fcaa78c4e8" name = "github.com/cloudtrust/common-service" packages = [ ".", @@ -38,16 +39,15 @@ "validation", ] pruneopts = "UT" - revision = "6f43146697b189b011f98619ca2674c29d769ea0" - version = "v2.0.1" + revision = "74a6646e4220c92027173b4be3bc8a818e313a64" [[projects]] - digest = "1:507116b0244b41be01dcbf553c56ab9045f2df92ff48bde722d155811ca0ab37" + branch = "ct-2375" + digest = "1:1b696d54587856a1607768ff288870210e6a1a27d886649faf80f92131fced44" name = "github.com/cloudtrust/keycloak-client" packages = ["."] pruneopts = "UT" - revision = "ce6d81a660e6e317d454ecfe2bb80057f8501531" - version = "v1.2.10" + revision = "dc1a849278cffb9d1749b20b36c74b659d38538d" [[projects]] digest = "1:910c5b111ca13127693df80a59be2c952ad97313626116c0c9895e7b588f2a29" @@ -140,7 +140,7 @@ version = "v1.3.4" [[projects]] - digest = "1:e02b687ade0c19c038ecce3ea326d756519adc4bba1203a9e76d620b12354892" + digest = "1:debcbc62c53851dab1fc881438a65449dd5ffa12f64f059fd6e32b938799513d" name = "github.com/google/flatbuffers" packages = ["go"] pruneopts = "UT" @@ -175,7 +175,7 @@ version = "v1.0.0" [[projects]] - digest = "1:9b73396bc7a21f88702fe3d314ca7860843c08f9c787bb47f008075f840df23d" + digest = "1:c266355b17e65dc0128f4a9df906567b28e135b774e0b395aab3d748af0871e2" name = "github.com/influxdata/influxdb" packages = [ "client/v2", @@ -313,12 +313,12 @@ version = "v1.0.5" [[projects]] - digest = "1:11118bd196646c6515fea3d6c43f66162833c6ae4939bfb229b9956d91c6cf17" + digest = "1:83d0e0f3f46dc86daf27e4d7c834c8c492db787c53c09d94183de7478db92142" name = "github.com/spf13/viper" packages = ["."] pruneopts = "UT" - revision = "b5bf975e5823809fb22c7644d008757f78a4259e" - version = "v1.4.0" + revision = "4525543ce4fe90f7970f5e2cdc300b8ffc8c0582" + version = "v1.6.2" [[projects]] digest = "1:5e8f46b412421d2d6cceea845d28ac46f3f5a5f60a6e86f0ee75e24fd43a02a9" @@ -328,6 +328,14 @@ revision = "3ebf1ddaeb260c4b1ae502a01c7844fa8c1fa0e9" version = "v1.5.1" +[[projects]] + digest = "1:f4b32291cad5efac2bfdba89ccde6aa04618b62ce06c1a571da2dc4f3f2677fb" + name = "github.com/subosito/gotenv" + packages = ["."] + pruneopts = "UT" + revision = "2ef7124db659d49edac6aa459693a15ae36c671a" + version = "v1.2.0" + [[projects]] digest = "1:54bf58828a4074c2304fcc52f018eb19fc02d5853ebd5121817330792c776734" name = "github.com/uber/jaeger-client-go" @@ -487,6 +495,14 @@ revision = "34f7caeaf69f4668a88f8294ec18665fd2756b84" version = "v2.0.4" +[[projects]] + digest = "1:ef4bd1cd2563d93d3f48352fc24d499a4a2b54c11932814173653ece7db13800" + name = "gopkg.in/ini.v1" + packages = ["."] + pruneopts = "UT" + revision = "32cf4f7e9c77f151e18b53067b55549b4d1d411d" + version = "v1.52.0" + [[projects]] digest = "1:3c4aaca5a82adc021322f239e0cf3f46852bb0b18ae050d0feab2e9e4c527462" name = "gopkg.in/square/go-jose.v2" diff --git a/Gopkg.toml b/Gopkg.toml index 4f65b74b1..6f9fbd5fc 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -27,11 +27,11 @@ [[constraint]] name = "github.com/cloudtrust/common-service" - version = "v2.0.1" + branch = "ct-2375" [[constraint]] name = "github.com/cloudtrust/keycloak-client" - version = "v1.2.10" + branch = "ct-2375" [[constraint]] name = "github.com/go-kit/kit" diff --git a/cmd/keycloakb/keycloak_bridge.go b/cmd/keycloakb/keycloak_bridge.go index 3aca519cb..466459d67 100644 --- a/cmd/keycloakb/keycloak_bridge.go +++ b/cmd/keycloakb/keycloak_bridge.go @@ -678,6 +678,13 @@ func main() { } } + // Tools for endpoint middleware + var idRetriever = keycloakb.NewRealmIDRetriever(keycloakClient) + var configurationReaderDBModule *configuration.ConfigurationReaderDBModule + { + configurationReaderDBModule = configuration.NewConfigurationReaderDBModule(configurationRoDBConn, logger) + } + // Export configuration var exportModule = export.NewModule(keycloakClient, logger) var cfgStorageModue = export.NewConfigStorageModule(eventsDBConn) @@ -843,10 +850,10 @@ func main() { var createShadowUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.CreateShadowUser) // KYC handlers - var kycGetActionsHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(kycEndpoints.GetActions) - var kycGetUserHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(kycEndpoints.GetUser) - var kycGetUserByUsernameHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(kycEndpoints.GetUserByUsername) - var kycValidateUserHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(kycEndpoints.ValidateUser) + var kycGetActionsHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, idRetriever, configurationReaderDBModule, logger)(kycEndpoints.GetActions) + var kycGetUserHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, idRetriever, configurationReaderDBModule, logger)(kycEndpoints.GetUser) + var kycGetUserByUsernameHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, idRetriever, configurationReaderDBModule, logger)(kycEndpoints.GetUserByUsername) + var kycValidateUserHandler = configureKYCHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, idRetriever, configurationReaderDBModule, logger)(kycEndpoints.ValidateUser) // actions managementSubroute.Path("/actions").Methods("GET").Handler(getManagementActionsHandler) @@ -1270,10 +1277,11 @@ func configureAccountHandler(ComponentName string, ComponentID string, idGenerat } } -func configureKYCHandler(ComponentName string, ComponentID string, idGenerator idgenerator.IDGenerator, keycloakClient *keycloak.Client, audienceRequired string, tracer tracing.OpentracingClient, logger log.Logger) func(endpoint endpoint.Endpoint) http.Handler { +func configureKYCHandler(ComponentName string, ComponentID string, idGenerator idgenerator.IDGenerator, keycloakClient *keycloak.Client, audienceRequired string, tracer tracing.OpentracingClient, idRetriever middleware.IDRetriever, configReader middleware.AdminConfigurationRetriever, logger log.Logger) func(endpoint endpoint.Endpoint) http.Handler { return func(endpoint endpoint.Endpoint) http.Handler { var handler http.Handler handler = kyc.MakeKYCHandler(endpoint, logger) + handler = middleware.MakeEndpointAvailableCheckMW("realm", configuration.CheckKeyPhysical, idRetriever, configReader, logger)(handler) handler = middleware.MakeHTTPCorrelationIDMW(idGenerator, tracer, logger, ComponentName, ComponentID)(handler) handler = middleware.MakeHTTPOIDCTokenValidationMW(keycloakClient, audienceRequired, logger)(handler) return handler diff --git a/internal/keycloakb/kcauthclient.go b/internal/keycloakb/kcauthclient.go index 5aebb6acd..9f187ebf1 100644 --- a/internal/keycloakb/kcauthclient.go +++ b/internal/keycloakb/kcauthclient.go @@ -3,6 +3,7 @@ package keycloakb import ( "context" + "github.com/cloudtrust/common-service/middleware" "github.com/cloudtrust/common-service/security" kc "github.com/cloudtrust/keycloak-client" ) @@ -11,6 +12,7 @@ import ( type KeycloakClient interface { GetGroupsOfUser(accessToken string, realmName, userID string) ([]kc.GroupRepresentation, error) GetGroup(accessToken string, realmName, groupID string) (kc.GroupRepresentation, error) + GetRealm(accessToken string, realmName string) (kc.RealmRepresentation, error) } type kcAuthClient struct { @@ -18,6 +20,10 @@ type kcAuthClient struct { logger Logger } +type idretriever struct { + kcClient KeycloakClient +} + // NewKeycloakAuthClient creates an adaptor for Authorization management to access Keycloak func NewKeycloakAuthClient(client KeycloakClient, logger Logger) security.KeycloakClient { return &kcAuthClient{ @@ -59,3 +65,21 @@ func (k *kcAuthClient) GetGroupName(ctx context.Context, accessToken string, rea return *(grp.Name), nil } + +// NewRealmIDRetriever is a tool use to convert a realm name in a realm ID +func NewRealmIDRetriever(kcClient KeycloakClient) middleware.IDRetriever { + return &idretriever{ + kcClient: kcClient, + } +} + +func (ir *idretriever) GetID(accessToken, name string) (string, error) { + var realm, err = ir.kcClient.GetRealm(accessToken, name) + if err != nil { + return "", err + } + if realm.Id == nil { + return "", nil + } + return *realm.Id, nil +} diff --git a/internal/keycloakb/kcauthclient_test.go b/internal/keycloakb/kcauthclient_test.go index 4f45f70ee..2f78aa0e3 100644 --- a/internal/keycloakb/kcauthclient_test.go +++ b/internal/keycloakb/kcauthclient_test.go @@ -62,29 +62,56 @@ func TestGetGroupNamesOfUserSuccess(t *testing.T) { }) } -func TestGetGroupNameError(t *testing.T) { - testKeycloakAuthClient(t, func(t *testing.T, mockKeycloak *mock.KeycloakClient, authClient security.KeycloakClient) { - mockKeycloak.EXPECT().GetGroup(accessToken, realm, groupID).Return(kc.GroupRepresentation{}, errors.New("error")).Times(1) - _, err := authClient.GetGroupName(context.TODO(), accessToken, realm, groupID) - assert.NotNil(t, err) +func TestGetGroupName(t *testing.T) { + t.Run("Error", func(t *testing.T) { + testKeycloakAuthClient(t, func(t *testing.T, mockKeycloak *mock.KeycloakClient, authClient security.KeycloakClient) { + mockKeycloak.EXPECT().GetGroup(accessToken, realm, groupID).Return(kc.GroupRepresentation{}, errors.New("error")).Times(1) + _, err := authClient.GetGroupName(context.TODO(), accessToken, realm, groupID) + assert.NotNil(t, err) + }) + }) + t.Run("Nil name", func(t *testing.T) { + testKeycloakAuthClient(t, func(t *testing.T, mockKeycloak *mock.KeycloakClient, authClient security.KeycloakClient) { + mockKeycloak.EXPECT().GetGroup(accessToken, realm, groupID).Return(kc.GroupRepresentation{Name: nil}, nil).Times(1) + res, err := authClient.GetGroupName(context.TODO(), accessToken, realm, groupID) + assert.Nil(t, err) + assert.Equal(t, "", res) + }) + }) + t.Run("Success", func(t *testing.T) { + testKeycloakAuthClient(t, func(t *testing.T, mockKeycloak *mock.KeycloakClient, authClient security.KeycloakClient) { + var groupname = "the name" + mockKeycloak.EXPECT().GetGroup(accessToken, realm, groupID).Return(kc.GroupRepresentation{Name: &groupname}, nil).Times(1) + res, err := authClient.GetGroupName(context.TODO(), accessToken, realm, groupID) + assert.Nil(t, err) + assert.Equal(t, groupname, res) + }) }) } -func TestGetGroupNameNilName(t *testing.T) { - testKeycloakAuthClient(t, func(t *testing.T, mockKeycloak *mock.KeycloakClient, authClient security.KeycloakClient) { - mockKeycloak.EXPECT().GetGroup(accessToken, realm, groupID).Return(kc.GroupRepresentation{Name: nil}, nil).Times(1) - res, err := authClient.GetGroupName(context.TODO(), accessToken, realm, groupID) +func TestGetID(t *testing.T) { + var mockCtrl = gomock.NewController(t) + defer mockCtrl.Finish() + + var mockKeycloak = mock.NewKeycloakClient(mockCtrl) + var idRetriever = NewRealmIDRetriever(mockKeycloak) + + t.Run("Error", func(t *testing.T) { + mockKeycloak.EXPECT().GetRealm(accessToken, realm).Return(kc.RealmRepresentation{}, errors.New("error")) + _, err := idRetriever.GetID(accessToken, realm) + assert.NotNil(t, err) + }) + t.Run("Nil name", func(t *testing.T) { + mockKeycloak.EXPECT().GetRealm(accessToken, realm).Return(kc.RealmRepresentation{}, nil) + id, err := idRetriever.GetID(accessToken, realm) assert.Nil(t, err) - assert.Equal(t, "", res) + assert.Equal(t, "", id) }) -} - -func TestGetGroupNameSuccess(t *testing.T) { - testKeycloakAuthClient(t, func(t *testing.T, mockKeycloak *mock.KeycloakClient, authClient security.KeycloakClient) { - var groupname = "the name" - mockKeycloak.EXPECT().GetGroup(accessToken, realm, groupID).Return(kc.GroupRepresentation{Name: &groupname}, nil).Times(1) - res, err := authClient.GetGroupName(context.TODO(), accessToken, realm, groupID) + t.Run("Success", func(t *testing.T) { + var id = "the-realm-identifier" + mockKeycloak.EXPECT().GetRealm(accessToken, realm).Return(kc.RealmRepresentation{Id: &id}, nil) + res, err := idRetriever.GetID(accessToken, realm) assert.Nil(t, err) - assert.Equal(t, groupname, res) + assert.Equal(t, id, res) }) }