mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-22 20:00:22 +00:00
MG-2456 - Refactor architecture (#2494)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com> Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com> Co-authored-by: Arvindh <30824765+arvindh123@users.noreply.github.com> Co-authored-by: Felix Gateru <felix.gateru@gmail.com>
This commit is contained in:
committed by
Dusan Borovcanin
parent
e29b54c54d
commit
243ccade0b
@@ -19,7 +19,7 @@ on:
|
||||
- "journal/api/**"
|
||||
- "provision/api/**"
|
||||
- "readers/api/**"
|
||||
- "things/api/**"
|
||||
- "clients/api/**"
|
||||
- "users/api/**"
|
||||
|
||||
env:
|
||||
@@ -29,7 +29,7 @@ env:
|
||||
USER_SECRET: 12345678
|
||||
DOMAIN_NAME: demo-test
|
||||
USERS_URL: http://localhost:9002
|
||||
THINGS_URL: http://localhost:9000
|
||||
CLIENTS_URL: http://localhost:9000
|
||||
HTTP_ADAPTER_URL: http://localhost:8008
|
||||
INVITATIONS_URL: http://localhost:9020
|
||||
AUTH_URL: http://localhost:8189
|
||||
@@ -65,8 +65,8 @@ jobs:
|
||||
export DOMAIN_ID=$(curl -sSX POST $DOMAINS_URL -H "Content-Type: application/json" -H "Authorization: Bearer $USER_TOKEN" -d "{\"name\":\"$DOMAIN_NAME\",\"alias\":\"$DOMAIN_NAME\"}" | jq -r .id)
|
||||
export USER_TOKEN=$(curl -sSX POST $TOKENS_URL -H "Content-Type: application/json" -d "{\"identity\": \"$USER_IDENTITY\",\"secret\": \"$USER_SECRET\",\"domain_id\": \"$DOMAIN_ID\"}" | jq -r .access_token)
|
||||
echo "USER_TOKEN=$USER_TOKEN" >> $GITHUB_ENV
|
||||
export THING_SECRET=$(magistrala-cli provision test | /usr/bin/grep -Eo '"secret": "[^"]+"' | awk 'NR % 2 == 0' | sed 's/"secret": "\(.*\)"/\1/')
|
||||
echo "THING_SECRET=$THING_SECRET" >> $GITHUB_ENV
|
||||
export CLIENT_SECRET=$(magistrala-cli provision test | /usr/bin/grep -Eo '"secret": "[^"]+"' | awk 'NR % 2 == 0' | sed 's/"secret": "\(.*\)"/\1/')
|
||||
echo "CLIENT_SECRET=$CLIENT_SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v3
|
||||
@@ -113,10 +113,10 @@ jobs:
|
||||
- "api/openapi/readers.yml"
|
||||
- "readers/api/**"
|
||||
|
||||
things:
|
||||
clients:
|
||||
- ".github/workflows/api-tests.yml"
|
||||
- "api/openapi/things.yml"
|
||||
- "things/api/**"
|
||||
- "api/openapi/clients.yml"
|
||||
- "clients/api/**"
|
||||
|
||||
users:
|
||||
- ".github/workflows/api-tests.yml"
|
||||
@@ -133,12 +133,12 @@ jobs:
|
||||
report: false
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --contrib-openapi-formats-uuid --hypothesis-suppress-health-check=filter_too_much --stateful=links'
|
||||
|
||||
- name: Run Things API tests
|
||||
if: steps.changes.outputs.things == 'true'
|
||||
- name: Run Clients API tests
|
||||
if: steps.changes.outputs.clients == 'true'
|
||||
uses: schemathesis/action@v1
|
||||
with:
|
||||
schema: api/openapi/things.yml
|
||||
base-url: ${{ env.THINGS_URL }}
|
||||
schema: api/openapi/clients.yml
|
||||
base-url: ${{ env.CLIENTS_URL }}
|
||||
checks: all
|
||||
report: false
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --contrib-openapi-formats-uuid --hypothesis-suppress-health-check=filter_too_much --stateful=links'
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
base-url: ${{ env.HTTP_ADAPTER_URL }}
|
||||
checks: all
|
||||
report: false
|
||||
args: '--header "Authorization: Thing ${{ env.THING_SECRET }}" --contrib-openapi-formats-uuid --hypothesis-suppress-health-check=filter_too_much --stateful=links'
|
||||
args: '--header "Authorization: Client ${{ env.CLIENT_SECRET }}" --contrib-openapi-formats-uuid --hypothesis-suppress-health-check=filter_too_much --stateful=links'
|
||||
|
||||
- name: Run Invitations API tests
|
||||
if: steps.changes.outputs.invitations == 'true'
|
||||
|
||||
@@ -49,8 +49,8 @@ jobs:
|
||||
- "users/clients.go"
|
||||
- "pkg/clients/clients.go"
|
||||
- "pkg/messaging/pubsub.go"
|
||||
- "things/postgres/clients.go"
|
||||
- "things/things.go"
|
||||
- "clients/postgres/clients.go"
|
||||
- "clients/clients.go"
|
||||
- "pkg/authz.go"
|
||||
- "pkg/authn.go"
|
||||
- "auth/domains.go"
|
||||
@@ -79,9 +79,9 @@ jobs:
|
||||
- name: Set up protoc
|
||||
if: steps.changes.outputs.proto == 'true'
|
||||
run: |
|
||||
PROTOC_VERSION=27.1
|
||||
PROTOC_GEN_VERSION=v1.34.2
|
||||
PROTOC_GRPC_VERSION=v1.4.0
|
||||
PROTOC_VERSION=28.3
|
||||
PROTOC_GEN_VERSION=v1.35.2
|
||||
PROTOC_GRPC_VERSION=v1.5.1
|
||||
|
||||
# Export the variables so they are available in future steps
|
||||
echo "PROTOC_VERSION=$PROTOC_VERSION" >> $GITHUB_ENV
|
||||
@@ -128,42 +128,56 @@ jobs:
|
||||
MOCKERY_VERSION=v2.43.2
|
||||
go install github.com/vektra/mockery/v2@$MOCKERY_VERSION
|
||||
|
||||
mv ./pkg/sdk/mocks/sdk.go ./pkg/sdk/mocks/sdk.go.tmp
|
||||
mv ./users/mocks/repository.go ./users/mocks/repository.go.tmp
|
||||
mv ./users/mocks/service.go ./users/mocks/service.go.tmp
|
||||
mv ./pkg/messaging/mocks/pubsub.go ./pkg/messaging/mocks/pubsub.go.tmp
|
||||
mv ./things/mocks/repository.go ./things/mocks/repository.go.tmp
|
||||
mv ./things/mocks/service.go ./things/mocks/service.go.tmp
|
||||
mv ./things/mocks/cache.go ./things/mocks/cache.go.tmp
|
||||
mv ./invitations/mocks/repository.go ./invitations/mocks/repository.go.tmp
|
||||
mv ./invitations/mocks/service.go ./invitations/mocks/service.go.tmp
|
||||
mv ./auth/mocks/token_client.go ./auth/mocks/token_client.go.tmp
|
||||
mv ./auth/mocks/authz.go ./auth/mocks/authz.go.tmp
|
||||
mv ./auth/mocks/domains.go ./auth/mocks/domains.go.tmp
|
||||
mv ./auth/mocks/keys.go ./auth/mocks/keys.go.tmp
|
||||
mv ./auth/mocks/service.go ./auth/mocks/service.go.tmp
|
||||
mv ./auth/mocks/token_client.go ./auth/mocks/token_client.go.tmp
|
||||
mv ./pkg/events/mocks/publisher.go ./pkg/events/mocks/publisher.go.tmp
|
||||
mv ./pkg/events/mocks/subscriber.go ./pkg/events/mocks/subscriber.go.tmp
|
||||
mv ./provision/mocks/service.go ./provision/mocks/service.go.tmp
|
||||
mv ./pkg/groups/mocks/repository.go ./pkg/groups/mocks/repository.go.tmp
|
||||
mv ./pkg/groups/mocks/service.go ./pkg/groups/mocks/service.go.tmp
|
||||
mv ./bootstrap/mocks/service.go ./bootstrap/mocks/service.go.tmp
|
||||
mv ./bootstrap/mocks/configs.go ./bootstrap/mocks/configs.go.tmp
|
||||
mv ./invitations/mocks/service.go ./invitations/mocks/service.go.tmp
|
||||
mv ./invitations/mocks/repository.go ./invitations/mocks/repository.go.tmp
|
||||
mv ./users/mocks/emailer.go ./users/mocks/emailer.go.tmp
|
||||
mv ./bootstrap/mocks/config_reader.go ./bootstrap/mocks/config_reader.go.tmp
|
||||
mv ./bootstrap/mocks/service.go ./bootstrap/mocks/service.go.tmp
|
||||
mv ./domains/mocks/domains_client.go ./domains/mocks/domains_client.go.tmp
|
||||
mv ./domains/mocks/repository.go ./domains/mocks/repository.go.tmp
|
||||
mv ./domains/mocks/service.go ./domains/mocks/service.go.tmp
|
||||
mv ./channels/mocks/repository.go ./channels/mocks/repository.go.tmp
|
||||
mv ./channels/mocks/channels_client.go ./channels/mocks/channels_client.go.tmp
|
||||
mv ./channels/mocks/service.go ./channels/mocks/service.go.tmp
|
||||
mv ./groups/private/mocks/service.go ./groups/private/mocks/service.go.tmp
|
||||
mv ./groups/mocks/repository.go ./groups/mocks/repository.go.tmp
|
||||
mv ./groups/mocks/groups_client.go ./groups/mocks/groups_client.go.tmp
|
||||
mv ./groups/mocks/service.go ./groups/mocks/service.go.tmp
|
||||
mv ./users/mocks/hasher.go ./users/mocks/hasher.go.tmp
|
||||
mv ./mqtt/mocks/events.go ./mqtt/mocks/events.go.tmp
|
||||
mv ./readers/mocks/messages.go ./readers/mocks/messages.go.tmp
|
||||
mv ./consumers/notifiers/mocks/notifier.go ./consumers/notifiers/mocks/notifier.go.tmp
|
||||
mv ./consumers/notifiers/mocks/service.go ./consumers/notifiers/mocks/service.go.tmp
|
||||
mv ./consumers/notifiers/mocks/repository.go ./consumers/notifiers/mocks/repository.go.tmp
|
||||
mv ./certs/mocks/pki.go ./certs/mocks/pki.go.tmp
|
||||
mv ./certs/mocks/service.go ./certs/mocks/service.go.tmp
|
||||
mv ./users/mocks/emailer.go ./users/mocks/emailer.go.tmp
|
||||
mv ./users/mocks/repository.go ./users/mocks/repository.go.tmp
|
||||
mv ./users/mocks/service.go ./users/mocks/service.go.tmp
|
||||
mv ./journal/mocks/repository.go ./journal/mocks/repository.go.tmp
|
||||
mv ./journal/mocks/service.go ./journal/mocks/service.go.tmp
|
||||
mv ./auth/mocks/domains_client.go ./auth/mocks/domains_client.go.tmp
|
||||
mv ./things/mocks/things_client.go ./things/mocks/things_client.go.tmp
|
||||
mv ./pkg/authz/mocks/authz.go ./pkg/authz/mocks/authz.go.tmp
|
||||
mv ./consumers/notifiers/mocks/notifier.go ./consumers/notifiers/mocks/notifier.go.tmp
|
||||
mv ./consumers/notifiers/mocks/repository.go ./consumers/notifiers/mocks/repository.go.tmp
|
||||
mv ./consumers/notifiers/mocks/service.go ./consumers/notifiers/mocks/service.go.tmp
|
||||
mv ./certs/mocks/pki.go ./certs/mocks/pki.go.tmp
|
||||
mv ./certs/mocks/service.go ./certs/mocks/service.go.tmp
|
||||
mv ./provision/mocks/service.go ./provision/mocks/service.go.tmp
|
||||
mv ./clients/private/mocks/service.go ./clients/private/mocks/service.go.tmp
|
||||
mv ./clients/mocks/repository.go ./clients/mocks/repository.go.tmp
|
||||
mv ./clients/mocks/clients_client.go ./clients/mocks/clients_client.go.tmp
|
||||
mv ./clients/mocks/cache.go ./clients/mocks/cache.go.tmp
|
||||
mv ./clients/mocks/service.go ./clients/mocks/service.go.tmp
|
||||
mv ./mqtt/mocks/events.go ./mqtt/mocks/events.go.tmp
|
||||
mv ./readers/mocks/messages.go ./readers/mocks/messages.go.tmp
|
||||
mv ./pkg/sdk/mocks/sdk.go ./pkg/sdk/mocks/sdk.go.tmp
|
||||
mv ./pkg/messaging/mocks/pubsub.go ./pkg/messaging/mocks/pubsub.go.tmp
|
||||
mv ./pkg/authn/mocks/authn.go ./pkg/authn/mocks/authn.go.tmp
|
||||
mv ./pkg/roles/mocks/rolesRepo.go ./pkg/roles/mocks/rolesRepo.go.tmp
|
||||
mv ./pkg/roles/mocks/provisioner.go ./pkg/roles/mocks/provisioner.go.tmp
|
||||
mv ./pkg/roles/mocks/rolemanager.go ./pkg/roles/mocks/rolemanager.go.tmp
|
||||
mv ./pkg/oauth2/mocks/provider.go ./pkg/oauth2/mocks/provider.go.tmp
|
||||
mv ./pkg/authz/mocks/authz.go ./pkg/authz/mocks/authz.go.tmp
|
||||
mv ./pkg/events/mocks/subscriber.go ./pkg/events/mocks/subscriber.go.tmp
|
||||
mv ./pkg/events/mocks/publisher.go ./pkg/events/mocks/publisher.go.tmp
|
||||
mv ./pkg/policies/mocks/evaluator.go ./pkg/policies/mocks/evaluator.go.tmp
|
||||
mv ./pkg/policies/mocks/service.go ./pkg/policies/mocks/service.go.tmp
|
||||
|
||||
make mocks
|
||||
|
||||
@@ -179,39 +193,53 @@ jobs:
|
||||
fi
|
||||
}
|
||||
|
||||
check_mock_changes ./pkg/sdk/mocks/sdk.go "SDK ./pkg/sdk/mocks/sdk.go"
|
||||
check_mock_changes ./users/mocks/repository.go "Users Repository ./users/mocks/repository.go"
|
||||
check_mock_changes ./users/mocks/service.go "Users Service ./users/mocks/service.go"
|
||||
check_mock_changes ./pkg/messaging/mocks/pubsub.go "PubSub ./pkg/messaging/mocks/pubsub.go"
|
||||
check_mock_changes ./things/mocks/repository.go "Things Repository ./things/mocks/repository.go"
|
||||
check_mock_changes ./things/mocks/service.go "Things Service ./things/mocks/service.go"
|
||||
check_mock_changes ./things/mocks/cache.go "Things Cache ./things/mocks/cache.go"
|
||||
check_mock_changes ./auth/mocks/authz.go "Auth Authz ./auth/mocks/authz.go"
|
||||
check_mock_changes ./auth/mocks/domains.go "Auth Domains ./auth/mocks/domains.go"
|
||||
check_mock_changes ./auth/mocks/keys.go "Auth Keys ./auth/mocks/keys.go"
|
||||
check_mock_changes ./auth/mocks/service.go "Auth Service ./auth/mocks/service.go"
|
||||
check_mock_changes ./pkg/authn/mocks/authn.go "Authn Service Client .pkg/authn/mocks/authn.go"
|
||||
check_mock_changes ./pkg/authz/mocks/authz.go "Authz Service Client .pkg/authz/mocks/authz.go"
|
||||
check_mock_changes ./pkg/events/mocks/publisher.go "ES Publisher ./pkg/events/mocks/publisher.go"
|
||||
check_mock_changes ./pkg/events/mocks/subscriber.go "EE Subscriber ./pkg/events/mocks/subscriber.go"
|
||||
check_mock_changes ./provision/mocks/service.go "Provision Service ./provision/mocks/service.go"
|
||||
check_mock_changes ./pkg/groups/mocks/repository.go "Groups Repository ./pkg/groups/mocks/repository.go"
|
||||
check_mock_changes ./pkg/groups/mocks/service.go "Groups Service ./pkg/groups/mocks/service.go"
|
||||
check_mock_changes ./bootstrap/mocks/service.go "Bootstrap Service ./bootstrap/mocks/service.go"
|
||||
check_mock_changes ./bootstrap/mocks/configs.go "Bootstrap Repository ./bootstrap/mocks/configs.go"
|
||||
check_mock_changes ./invitations/mocks/service.go "Invitations Service ./invitations/mocks/service.go"
|
||||
check_mock_changes ./invitations/mocks/repository.go "Invitations Repository ./invitations/mocks/repository.go"
|
||||
check_mock_changes ./users/mocks/emailer.go "Users Emailer ./users/mocks/emailer.go"
|
||||
check_mock_changes ./users/mocks/hasher.go "Users Hasher ./users/mocks/hasher.go"
|
||||
check_mock_changes ./mqtt/mocks/events.go "MQTT Events Store ./mqtt/mocks/events.go"
|
||||
check_mock_changes ./readers/mocks/messages.go "Message Readers ./readers/mocks/messages.go"
|
||||
check_mock_changes ./consumers/notifiers/mocks/notifier.go "Notifiers Notifier ./consumers/notifiers/mocks/notifier.go"
|
||||
check_mock_changes ./consumers/notifiers/mocks/service.go "Notifiers Service ./consumers/notifiers/mocks/service.go"
|
||||
check_mock_changes ./consumers/notifiers/mocks/repository.go "Notifiers Repository ./consumers/notifiers/mocks/repository.go"
|
||||
check_mock_changes ./certs/mocks/pki.go "PKI ./certs/mocks/pki.go"
|
||||
check_mock_changes ./certs/mocks/service.go "Certs Service ./certs/mocks/service.go"
|
||||
check_mock_changes ./journal/mocks/repository.go "Journal Repository ./journal/mocks/repository.go"
|
||||
check_mock_changes ./journal/mocks/service.go "Journal Service ./journal/mocks/service.go"
|
||||
check_mock_changes ./auth/mocks/domains_client.go "Domains Service Client ./auth/mocks/domains_client.go"
|
||||
check_mock_changes ./auth/mocks/token_client.go "Token Service Client ./auth/mocks/token_client.go"
|
||||
check_mock_changes ./things/mocks/things_client.go "Things Service Client things/mocks/things_client.go"
|
||||
check_mock_changes ./invitations/mocks/repository.go " ./invitations/mocks/repository.go"
|
||||
check_mock_changes ./invitations/mocks/service.go " ./invitations/mocks/service.go"
|
||||
check_mock_changes ./auth/mocks/token_client.go " ./auth/mocks/token_client.go"
|
||||
check_mock_changes ./auth/mocks/authz.go " ./auth/mocks/authz.go"
|
||||
check_mock_changes ./auth/mocks/keys.go " ./auth/mocks/keys.go"
|
||||
check_mock_changes ./auth/mocks/service.go " ./auth/mocks/service.go"
|
||||
check_mock_changes ./bootstrap/mocks/configs.go " ./bootstrap/mocks/configs.go"
|
||||
check_mock_changes ./bootstrap/mocks/config_reader.go " ./bootstrap/mocks/config_reader.go"
|
||||
check_mock_changes ./bootstrap/mocks/service.go " ./bootstrap/mocks/service.go"
|
||||
check_mock_changes ./domains/mocks/domains_client.go " ./domains/mocks/domains_client.go"
|
||||
check_mock_changes ./domains/mocks/repository.go " ./domains/mocks/repository.go"
|
||||
check_mock_changes ./domains/mocks/service.go " ./domains/mocks/service.go"
|
||||
check_mock_changes ./channels/mocks/repository.go " ./channels/mocks/repository.go"
|
||||
check_mock_changes ./channels/mocks/channels_client.go " ./channels/mocks/channels_client.go"
|
||||
check_mock_changes ./channels/mocks/service.go " ./channels/mocks/service.go"
|
||||
check_mock_changes ./groups/private/mocks/service.go " ./groups/private/mocks/service.go"
|
||||
check_mock_changes ./groups/mocks/repository.go " ./groups/mocks/repository.go"
|
||||
check_mock_changes ./groups/mocks/groups_client.go " ./groups/mocks/groups_client.go"
|
||||
check_mock_changes ./groups/mocks/service.go " ./groups/mocks/service.go"
|
||||
check_mock_changes ./users/mocks/hasher.go " ./users/mocks/hasher.go"
|
||||
check_mock_changes ./users/mocks/emailer.go " ./users/mocks/emailer.go"
|
||||
check_mock_changes ./users/mocks/repository.go " ./users/mocks/repository.go"
|
||||
check_mock_changes ./users/mocks/service.go " ./users/mocks/service.go"
|
||||
check_mock_changes ./journal/mocks/repository.go " ./journal/mocks/repository.go"
|
||||
check_mock_changes ./journal/mocks/service.go " ./journal/mocks/service.go"
|
||||
check_mock_changes ./consumers/notifiers/mocks/notifier.go " ./consumers/notifiers/mocks/notifier.go"
|
||||
check_mock_changes ./consumers/notifiers/mocks/repository.go " ./consumers/notifiers/mocks/repository.go"
|
||||
check_mock_changes ./consumers/notifiers/mocks/service.go " ./consumers/notifiers/mocks/service.go"
|
||||
check_mock_changes ./certs/mocks/pki.go " ./certs/mocks/pki.go"
|
||||
check_mock_changes ./certs/mocks/service.go " ./certs/mocks/service.go"
|
||||
check_mock_changes ./provision/mocks/service.go " ./provision/mocks/service.go"
|
||||
check_mock_changes ./clients/private/mocks/service.go " ./clients/private/mocks/service.go"
|
||||
check_mock_changes ./clients/mocks/repository.go " ./clients/mocks/repository.go"
|
||||
check_mock_changes ./clients/mocks/clients_client.go " ./clients/mocks/clients_client.go"
|
||||
check_mock_changes ./clients/mocks/cache.go " ./clients/mocks/cache.go"
|
||||
check_mock_changes ./clients/mocks/service.go " ./clients/mocks/service.go"
|
||||
check_mock_changes ./mqtt/mocks/events.go " ./mqtt/mocks/events.go"
|
||||
check_mock_changes ./readers/mocks/messages.go " ./readers/mocks/messages.go"
|
||||
check_mock_changes ./pkg/sdk/mocks/sdk.go " ./pkg/sdk/mocks/sdk.go"
|
||||
check_mock_changes ./pkg/messaging/mocks/pubsub.go " ./pkg/messaging/mocks/pubsub.go"
|
||||
check_mock_changes ./pkg/authn/mocks/authn.go " ./pkg/authn/mocks/authn.go"
|
||||
check_mock_changes ./pkg/roles/mocks/rolesRepo.go " ./pkg/roles/mocks/rolesRepo.go"
|
||||
check_mock_changes ./pkg/roles/mocks/provisioner.go " ./pkg/roles/mocks/provisioner.go"
|
||||
check_mock_changes ./pkg/roles/mocks/rolemanager.go " ./pkg/roles/mocks/rolemanager.go"
|
||||
check_mock_changes ./pkg/oauth2/mocks/provider.go " ./pkg/oauth2/mocks/provider.go"
|
||||
check_mock_changes ./pkg/authz/mocks/authz.go " ./pkg/authz/mocks/authz.go"
|
||||
check_mock_changes ./pkg/events/mocks/subscriber.go " ./pkg/events/mocks/subscriber.go"
|
||||
check_mock_changes ./pkg/events/mocks/publisher.go " ./pkg/events/mocks/publisher.go"
|
||||
check_mock_changes ./pkg/policies/mocks/evaluator.go " ./pkg/policies/mocks/evaluator.go"
|
||||
check_mock_changes ./pkg/policies/mocks/service.go " ./pkg/policies/mocks/service.go"
|
||||
|
||||
+12
-12
@@ -111,7 +111,7 @@ jobs:
|
||||
- "cmd/coap/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "clients/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
consumers:
|
||||
@@ -140,7 +140,7 @@ jobs:
|
||||
- "cmd/http/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "clients/**"
|
||||
- "pkg/messaging/**"
|
||||
- "logger/**"
|
||||
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
- "cmd/mqtt/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "clients/**"
|
||||
- "pkg/messaging/**"
|
||||
- "logger/**"
|
||||
- "pkg/events/**"
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
- "invitations/**"
|
||||
- "provision/**"
|
||||
- "readers/**"
|
||||
- "things/**"
|
||||
- "clients/**"
|
||||
- "users/**"
|
||||
|
||||
pkg-transformers:
|
||||
@@ -221,12 +221,12 @@ jobs:
|
||||
- "cmd/timescale-reader/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "clients/**"
|
||||
- "auth/**"
|
||||
|
||||
things:
|
||||
- "things/**"
|
||||
- "cmd/things/**"
|
||||
clients:
|
||||
- "clients/**"
|
||||
- "cmd/clients/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
@@ -249,7 +249,7 @@ jobs:
|
||||
- "cmd/ws/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "things/**"
|
||||
- "clients/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
- name: Create coverage directory
|
||||
@@ -366,10 +366,10 @@ jobs:
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/readers.out ./readers/...
|
||||
|
||||
- name: Run things tests
|
||||
if: steps.changes.outputs.things == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
- name: Run clients tests
|
||||
if: steps.changes.outputs.clients == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
run: |
|
||||
go test --race -v -count=1 -coverprofile=coverage/things.out ./things/...
|
||||
go test --race -v -count=1 -coverprofile=coverage/clients.out ./clients/...
|
||||
|
||||
- name: Run users tests
|
||||
if: steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
MG_DOCKER_IMAGE_NAME_PREFIX ?= magistrala
|
||||
BUILD_DIR = build
|
||||
SERVICES = auth users things http coap ws postgres-writer postgres-reader timescale-writer \
|
||||
MG_DOCKER_IMAGE_NAME_PREFIX ?= supermq
|
||||
BUILD_DIR ?= build
|
||||
SERVICES = auth users clients groups channels domains http coap ws postgres-writer postgres-reader timescale-writer \
|
||||
timescale-reader cli bootstrap mqtt provision certs invitations journal
|
||||
TEST_API_SERVICES = journal auth bootstrap certs http invitations notifiers provision readers things users
|
||||
TEST_API_SERVICES = journal auth bootstrap certs http invitations notifiers provision readers clients users
|
||||
TEST_API = $(addprefix test_api_,$(TEST_API_SERVICES))
|
||||
DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
@@ -19,10 +19,14 @@ empty:=
|
||||
space:= $(empty) $(empty)
|
||||
# Docker compose project name should follow this guidelines: https://docs.docker.com/compose/reference/#use--p-to-specify-a-project-name
|
||||
DOCKER_PROJECT ?= $(shell echo $(subst $(space),,$(USER_REPO)) | tr -c -s '[:alnum:][=-=]' '_' | tr '[:upper:]' '[:lower:]')
|
||||
DOCKER_COMPOSE_COMMANDS_SUPPORTED := up down config
|
||||
DOCKER_COMPOSE_COMMANDS_SUPPORTED := up down config restart
|
||||
DEFAULT_DOCKER_COMPOSE_COMMAND := up
|
||||
GRPC_MTLS_CERT_FILES_EXISTS = 0
|
||||
MOCKERY_VERSION=v2.43.2
|
||||
INTERNAL_PROTO_GEN_OUT_DIR=internal/grpc
|
||||
INTERNAL_PROTO_DIR=internal/proto
|
||||
INTERNAL_PROTO_FILES := $(shell find $(INTERNAL_PROTO_DIR) -name "*.proto" | sed 's|$(INTERNAL_PROTO_DIR)/||')
|
||||
|
||||
ifneq ($(MG_MESSAGE_BROKER_TYPE),)
|
||||
MG_MESSAGE_BROKER_TYPE := $(MG_MESSAGE_BROKER_TYPE)
|
||||
else
|
||||
@@ -38,9 +42,9 @@ endif
|
||||
define compile_service
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
|
||||
go build -tags $(MG_MESSAGE_BROKER_TYPE) --tags $(MG_ES_TYPE) -ldflags "-s -w \
|
||||
-X 'github.com/absmach/magistrala.BuildTime=$(TIME)' \
|
||||
-X 'github.com/absmach/magistrala.Version=$(VERSION)' \
|
||||
-X 'github.com/absmach/magistrala.Commit=$(COMMIT)'" \
|
||||
-X 'github.com/absmach/supermq.BuildTime=$(TIME)' \
|
||||
-X 'github.com/absmach/supermq.Version=$(VERSION)' \
|
||||
-X 'github.com/absmach/supermq.Commit=$(COMMIT)'" \
|
||||
-o ${BUILD_DIR}/$(1) cmd/$(1)/main.go
|
||||
endef
|
||||
|
||||
@@ -138,8 +142,8 @@ define test_api_service
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
@if [ "$(svc)" = "http" ] && [ -z "$(THING_SECRET)" ]; then \
|
||||
echo "THING_SECRET is not set"; \
|
||||
@if [ "$(svc)" = "http" ] && [ -z "$(CLIENT_SECRET)" ]; then \
|
||||
echo "CLIENT_SECRET is not set"; \
|
||||
echo "Please set it to a valid secret"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@@ -148,7 +152,7 @@ define test_api_service
|
||||
st run api/openapi/$(svc).yml \
|
||||
--checks all \
|
||||
--base-url $(2) \
|
||||
--header "Authorization: Thing $(THING_SECRET)" \
|
||||
--header "Authorization: Client $(CLIENT_SECRET)" \
|
||||
--contrib-openapi-formats-uuid \
|
||||
--hypothesis-suppress-health-check=filter_too_much \
|
||||
--stateful=links; \
|
||||
@@ -164,7 +168,7 @@ define test_api_service
|
||||
endef
|
||||
|
||||
test_api_users: TEST_API_URL := http://localhost:9002
|
||||
test_api_things: TEST_API_URL := http://localhost:9000
|
||||
test_api_clients: TEST_API_URL := http://localhost:9000
|
||||
test_api_http: TEST_API_URL := http://localhost:8008
|
||||
test_api_invitations: TEST_API_URL := http://localhost:9020
|
||||
test_api_auth: TEST_API_URL := http://localhost:8189
|
||||
@@ -179,7 +183,8 @@ $(TEST_API):
|
||||
|
||||
proto:
|
||||
protoc -I. --go_out=. --go_opt=paths=source_relative pkg/messaging/*.proto
|
||||
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./*.proto
|
||||
mkdir -p $(INTERNAL_PROTO_GEN_OUT_DIR)
|
||||
protoc -I $(INTERNAL_PROTO_DIR) --go_out=$(INTERNAL_PROTO_GEN_OUT_DIR) --go_opt=paths=source_relative --go-grpc_out=$(INTERNAL_PROTO_GEN_OUT_DIR) --go-grpc_opt=paths=source_relative $(INTERNAL_PROTO_FILES)
|
||||
|
||||
$(FILTERED_SERVICES):
|
||||
$(call compile_service,$(@))
|
||||
@@ -218,7 +223,7 @@ rundev:
|
||||
cd scripts && ./run.sh
|
||||
|
||||
grpc_mtls_certs:
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs things_grpc_certs
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
|
||||
|
||||
check_tls:
|
||||
ifeq ($(GRPC_TLS),true)
|
||||
@@ -244,7 +249,7 @@ check_certs: check_mtls check_tls
|
||||
ifeq ($(GRPC_MTLS_CERT_FILES_EXISTS),0)
|
||||
ifeq ($(filter true,$(GRPC_MTLS) $(GRPC_TLS)),true)
|
||||
ifeq ($(filter $(DEFAULT_DOCKER_COMPOSE_COMMAND),$(DOCKER_COMPOSE_COMMAND)),$(DEFAULT_DOCKER_COMPOSE_COMMAND))
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs things_grpc_certs
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -257,3 +262,6 @@ run_addons: check_certs
|
||||
@for SVC in $(RUN_ADDON_ARGS); do \
|
||||
MG_ADDONS_CERTS_PATH_PREFIX="../." docker compose -f docker/addons/$$SVC/docker-compose.yml -p $(DOCKER_PROJECT) --env-file ./docker/.env $(DOCKER_COMPOSE_COMMAND) $(args) & \
|
||||
done
|
||||
|
||||
run_live: check_certs
|
||||
GOPATH=$(go env GOPATH) docker compose -f docker/docker-compose.yml -f docker/docker-compose-live.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
@@ -137,7 +137,8 @@ You like SuperMQ and you would like to make it your day job? We're always lookin
|
||||
|
||||
[Apache-2.0](LICENSE)
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fabsmach%2Fmagistrala?ref=badge_large&issueType=license)
|
||||
[![FOSSA Status][FOSSA]][FOSSA]
|
||||
|
||||
## Data Collection for SuperMQ
|
||||
|
||||
SuperMQ is committed to continuously improving its services and ensuring a seamless experience for its users. To achieve this, we collect certain data from your deployments. Rest assured, this data is collected solely for the purpose of enhancing SuperMQ and is not used with any malicious intent. The deployment summary can be found on our [website][callhome].
|
||||
@@ -189,3 +190,4 @@ By utilizing SuperMQ, you actively contribute to its improvement. Together, we c
|
||||
[rodneyosodo]: https://github.com/rodneyosodo
|
||||
[callhome]: https://deployments.magistrala.abstractmachines.fr/
|
||||
[contrib]: https://www.github.com/absmach/mg-contrib
|
||||
[FOSSA]: https://app.fossa.com/api/projects/git%2Bgithub.com%2Fabsmach%2Fsupermq.svg?type=small
|
||||
@@ -17,8 +17,8 @@ info:
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: 'https://github.com/absmach/magistrala/blob/main/LICENSE'
|
||||
|
||||
|
||||
|
||||
|
||||
defaultContentType: application/json
|
||||
|
||||
servers:
|
||||
@@ -33,7 +33,7 @@ servers:
|
||||
enum:
|
||||
- '1883'
|
||||
- '8883'
|
||||
security:
|
||||
security:
|
||||
- user-password: []
|
||||
|
||||
channels:
|
||||
@@ -45,7 +45,7 @@ channels:
|
||||
required: true
|
||||
subtopic:
|
||||
$ref: '#/components/parameters/subtopic'
|
||||
in: path
|
||||
in: path
|
||||
required: false
|
||||
|
||||
publish:
|
||||
@@ -88,7 +88,7 @@ components:
|
||||
|
||||
parameters:
|
||||
channelID:
|
||||
description: Channel ID connected to the Thing ID defined in the username.
|
||||
description: Channel ID connected to the Client ID defined in the username.
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
@@ -97,13 +97,13 @@ components:
|
||||
schema:
|
||||
type: string
|
||||
default: ''
|
||||
|
||||
|
||||
securitySchemes:
|
||||
user-password:
|
||||
type: userPassword
|
||||
description: |
|
||||
username is thing ID connected to the channel defined in the mqtt topic and
|
||||
password is thing key corresponding to the thing ID
|
||||
username is client ID connected to the channel defined in the mqtt topic and
|
||||
password is client secret corresponding to the client ID
|
||||
|
||||
operationTraits:
|
||||
mqtt:
|
||||
|
||||
@@ -126,7 +126,7 @@ components:
|
||||
```
|
||||
parameters:
|
||||
channelID:
|
||||
description: Channel ID connected to the Thing ID defined in the username.
|
||||
description: Channel ID connected to the Client ID defined in the username.
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
@@ -141,4 +141,4 @@ components:
|
||||
scheme: bearer
|
||||
bearerFormat: uuid
|
||||
description: |
|
||||
* Thing access: "Authorization: Thing <thing_key>"
|
||||
* Client access: "Authorization: Client <client_key>"
|
||||
|
||||
@@ -31,7 +31,7 @@ tags:
|
||||
externalDocs:
|
||||
description: Find out more about domains
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
|
||||
- name: Health
|
||||
description: Service health check endpoint.
|
||||
externalDocs:
|
||||
@@ -549,7 +549,7 @@ components:
|
||||
metadata:
|
||||
type: object
|
||||
example: { "domain": "example.com" }
|
||||
description: Arbitrary, object-encoded thing's data.
|
||||
description: Arbitrary, object-encoded client's data.
|
||||
alias:
|
||||
type: string
|
||||
example: domain alias
|
||||
|
||||
+38
-38
@@ -5,7 +5,7 @@ openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Bootstrap service
|
||||
description: |
|
||||
HTTP API for managing platform things configuration.
|
||||
HTTP API for managing platform clients configuration.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
@@ -27,7 +27,7 @@ tags:
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
paths:
|
||||
/{domainID}/things/configs:
|
||||
/{domainID}/clients/configs:
|
||||
post:
|
||||
operationId: createConfig
|
||||
summary: Adds new config
|
||||
@@ -60,7 +60,7 @@ paths:
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
"503":
|
||||
description: Failed to receive response from the things service.
|
||||
description: Failed to receive response from the clients service.
|
||||
get:
|
||||
operationId: getConfigs
|
||||
summary: Retrieves managed configs
|
||||
@@ -88,7 +88,7 @@ paths:
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/{domainID}/things/configs/{configId}:
|
||||
/{domainID}/clients/configs/{configId}:
|
||||
get:
|
||||
operationId: getConfig
|
||||
summary: Retrieves config info (with channels).
|
||||
@@ -118,7 +118,7 @@ paths:
|
||||
description: |
|
||||
Update is performed by replacing the current resource data with values
|
||||
provided in a request payload. Note that the owner, ID, external ID,
|
||||
external key, Magistrala Thing ID and key cannot be changed.
|
||||
external key, Magistrala Client ID and key cannot be changed.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
@@ -167,7 +167,7 @@ paths:
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/{domainID}/things/configs/certs/{configId}:
|
||||
/{domainID}/clients/configs/certs/{configId}:
|
||||
patch:
|
||||
operationId: updateConfigCerts
|
||||
summary: Updates certs
|
||||
@@ -199,13 +199,13 @@ paths:
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/{domainID}/things/configs/connections/{configId}:
|
||||
/{domainID}/clients/configs/connections/{configId}:
|
||||
put:
|
||||
operationId: updateConfigConnections
|
||||
summary: Updates channels the thing is connected to
|
||||
summary: Updates channels the client is connected to
|
||||
description: |
|
||||
Update connections performs update of the channel list corresponding
|
||||
Thing is connected to.
|
||||
Client is connected to.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
@@ -230,7 +230,7 @@ paths:
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/bootstrap/{externalId}:
|
||||
/clients/bootstrap/{externalId}:
|
||||
get:
|
||||
operationId: getBootstrapConfig
|
||||
summary: Retrieves configuration.
|
||||
@@ -255,7 +255,7 @@ paths:
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/bootstrap/secure/{externalId}:
|
||||
/clients/bootstrap/secure/{externalId}:
|
||||
get:
|
||||
operationId: getSecureBootstrapConfig
|
||||
summary: Retrieves configuration.
|
||||
@@ -281,13 +281,13 @@ paths:
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/{domainID}/things/state/{configId}:
|
||||
/{domainID}/clients/state/{configId}:
|
||||
put:
|
||||
operationId: updateConfigState
|
||||
summary: Updates Config state.
|
||||
description: |
|
||||
Updating state represents enabling/disabling Config, i.e. connecting
|
||||
and disconnecting corresponding Magistrala Thing to the list of Channels.
|
||||
and disconnecting corresponding Magistrala Client to the list of Channels.
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
@@ -330,14 +330,14 @@ components:
|
||||
Config:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing ID.
|
||||
magistrala_key:
|
||||
description: Corresponding Magistrala Client ID.
|
||||
magistrala_secret:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing key.
|
||||
description: Corresponding Magistrala Client key.
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
@@ -402,14 +402,14 @@ components:
|
||||
BootstrapConfig:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing ID.
|
||||
thing_key:
|
||||
description: Corresponding Magistrala Client ID.
|
||||
client_key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing key.
|
||||
description: Corresponding Magistrala Client key.
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
@@ -428,17 +428,17 @@ components:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- thing_id
|
||||
- thing_key
|
||||
- client_id
|
||||
- client_key
|
||||
- channels
|
||||
- content
|
||||
ConfigUpdateCerts:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing ID.
|
||||
description: Corresponding Magistrala Client ID.
|
||||
client_cert:
|
||||
type: string
|
||||
description: Client certificate.
|
||||
@@ -449,15 +449,15 @@ components:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- thing_id
|
||||
- thing_key
|
||||
- client_id
|
||||
- client_key
|
||||
- channels
|
||||
- content
|
||||
|
||||
parameters:
|
||||
ConfigId:
|
||||
name: configId
|
||||
description: Unique Config identifier. It's the ID of the corresponding Thing.
|
||||
description: Unique Config identifier. It's the ID of the corresponding Client.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
@@ -519,10 +519,10 @@ components:
|
||||
external_key:
|
||||
type: string
|
||||
description: External key.
|
||||
thing_id:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: ID of the corresponding Magistrala Thing.
|
||||
description: ID of the corresponding Magistrala Client.
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
@@ -535,17 +535,17 @@ components:
|
||||
type: string
|
||||
client_cert:
|
||||
type: string
|
||||
description: Thing Certificate.
|
||||
description: Client Certificate.
|
||||
client_key:
|
||||
type: string
|
||||
description: Thing Private Key.
|
||||
description: Client Private Key.
|
||||
ca_cert:
|
||||
type: string
|
||||
required:
|
||||
- external_id
|
||||
- external_key
|
||||
ConfigUpdateReq:
|
||||
description: JSON-formatted document describing the updated thing.
|
||||
description: JSON-formatted document describing the updated client.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -559,7 +559,7 @@ components:
|
||||
- content
|
||||
- name
|
||||
ConfigCertUpdateReq:
|
||||
description: JSON-formatted document describing the updated thing.
|
||||
description: JSON-formatted document describing the updated client.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -572,7 +572,7 @@ components:
|
||||
ca_cert:
|
||||
type: string
|
||||
ConfigConnUpdateReq:
|
||||
description: Array if IDs the thing is be connected to.
|
||||
description: Array if IDs the client is be connected to.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -603,7 +603,7 @@ components:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created configuration's relative URL (i.e. /things/configs/{configId}).
|
||||
description: Created configuration's relative URL (i.e. /clients/configs/{configId}).
|
||||
ConfigListRes:
|
||||
description: Data retrieved. Configs from this list don't contain channels.
|
||||
content:
|
||||
@@ -673,14 +673,14 @@ components:
|
||||
scheme: bearer
|
||||
bearerFormat: string
|
||||
description: |
|
||||
* Things access: "Authorization: Thing <external_key>"
|
||||
* Clients access: "Authorization: Client <external_key>"
|
||||
|
||||
bootstrapEncAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: aes-sha256-uuid
|
||||
description: |
|
||||
* Things access: "Authorization: Thing <external_enc_key>"
|
||||
* Clients access: "Authorization: Client <external_enc_key>"
|
||||
Hex-encoded configuration external key encrypted using
|
||||
the AES algorithm and SHA256 sum of the external key
|
||||
itself as an encryption key.
|
||||
|
||||
+15
-15
@@ -30,8 +30,8 @@ paths:
|
||||
/{domainID}/certs:
|
||||
post:
|
||||
operationId: createCert
|
||||
summary: Creates a certificate for thing
|
||||
description: Creates a certificate for thing
|
||||
summary: Creates a certificate for client
|
||||
description: Creates a certificate for client
|
||||
tags:
|
||||
- certs
|
||||
parameters:
|
||||
@@ -106,17 +106,17 @@ paths:
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/{domainID}/serials/{thingID}:
|
||||
/{domainID}/serials/{clientID}:
|
||||
get:
|
||||
operationId: getSerials
|
||||
summary: Retrieves certificates' serial IDs
|
||||
description: |
|
||||
Retrieves a list of certificates' serial IDs for a given thing ID.
|
||||
Retrieves a list of certificates' serial IDs for a given client ID.
|
||||
tags:
|
||||
- certs
|
||||
parameters:
|
||||
- $ref: "auth.yml#/components/parameters/DomainID"
|
||||
- $ref: "#/components/parameters/ThingID"
|
||||
- $ref: "#/components/parameters/ClientID"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/SerialsPageRes"
|
||||
@@ -147,9 +147,9 @@ paths:
|
||||
|
||||
components:
|
||||
parameters:
|
||||
ThingID:
|
||||
name: thingID
|
||||
description: Thing ID
|
||||
ClientID:
|
||||
name: clientID
|
||||
description: Client ID
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
@@ -168,10 +168,10 @@ components:
|
||||
Cert:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Magistrala Thing ID.
|
||||
description: Corresponding Magistrala Client ID.
|
||||
client_cert:
|
||||
type: string
|
||||
description: Client Certificate.
|
||||
@@ -240,18 +240,18 @@ components:
|
||||
requestBodies:
|
||||
CertReq:
|
||||
description: |
|
||||
Issues a certificate that is required for mTLS. To create a certificate for a thing
|
||||
provide a thing id, data identifying particular thing will be embedded into the Certificate.
|
||||
Issues a certificate that is required for mTLS. To create a certificate for a client
|
||||
provide a client id, data identifying particular client will be embedded into the Certificate.
|
||||
x509 and ECC certificates are supported when using when Vault is used as PKI.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- thing_id
|
||||
- client_id
|
||||
- ttl
|
||||
properties:
|
||||
thing_id:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
ttl:
|
||||
@@ -271,7 +271,7 @@ components:
|
||||
serial:
|
||||
operationId: getSerials
|
||||
parameters:
|
||||
thingID: $response.body#/thing_id
|
||||
clientID: $response.body#/client_id
|
||||
delete:
|
||||
operationId: revokeCert
|
||||
parameters:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -169,13 +169,13 @@ components:
|
||||
scheme: bearer
|
||||
bearerFormat: uuid
|
||||
description: |
|
||||
* Thing access: "Authorization: Thing <thing_key>"
|
||||
* Client access: "Authorization: Client <client_key>"
|
||||
|
||||
basicAuth:
|
||||
type: http
|
||||
scheme: basic
|
||||
description: |
|
||||
* Things access: "Authorization: Basic <base64-encoded_credentials>"
|
||||
* Clients access: "Authorization: Basic <base64-encoded_credentials>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
|
||||
@@ -197,13 +197,13 @@ components:
|
||||
|
||||
entity_type:
|
||||
name: entityType
|
||||
description: Type of entity, e.g. user, group, thing, etc.entityType
|
||||
description: Type of entity, e.g. user, group, client, etc.entityType
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- group
|
||||
- thing
|
||||
- client
|
||||
- channel
|
||||
required: true
|
||||
example: group
|
||||
|
||||
@@ -179,7 +179,7 @@ components:
|
||||
required: false
|
||||
Publisher:
|
||||
name: Publisher
|
||||
description: Unique thing identifier.
|
||||
description: Unique client identifier.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
@@ -302,13 +302,13 @@ components:
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
thingAuth:
|
||||
clientAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: uuid
|
||||
description: |
|
||||
* Things access: "Authorization: Thing <thing_key>"
|
||||
* Clients access: "Authorization: Client <client_key>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
- thingAuth: []
|
||||
- clientAuth: []
|
||||
|
||||
-993
@@ -1,993 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.34.2
|
||||
// protoc v5.27.1
|
||||
// source: auth.proto
|
||||
|
||||
package magistrala
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// If a token is not carrying any information itself, the type
|
||||
// field can be used to determine how to validate the token.
|
||||
// Also, different tokens can be encoded in different ways.
|
||||
type Token struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
|
||||
RefreshToken *string `protobuf:"bytes,2,opt,name=refresh_token,json=refreshToken,proto3,oneof" json:"refresh_token,omitempty"`
|
||||
AccessType string `protobuf:"bytes,3,opt,name=access_type,json=accessType,proto3" json:"access_type,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Token) Reset() {
|
||||
*x = Token{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Token) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Token) ProtoMessage() {}
|
||||
|
||||
func (x *Token) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Token.ProtoReflect.Descriptor instead.
|
||||
func (*Token) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Token) GetAccessToken() string {
|
||||
if x != nil {
|
||||
return x.AccessToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Token) GetRefreshToken() string {
|
||||
if x != nil && x.RefreshToken != nil {
|
||||
return *x.RefreshToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Token) GetAccessType() string {
|
||||
if x != nil {
|
||||
return x.AccessType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AuthNReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AuthNReq) Reset() {
|
||||
*x = AuthNReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AuthNReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthNReq) ProtoMessage() {}
|
||||
|
||||
func (x *AuthNReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AuthNReq.ProtoReflect.Descriptor instead.
|
||||
func (*AuthNReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *AuthNReq) GetToken() string {
|
||||
if x != nil {
|
||||
return x.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AuthNRes struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // change "id" to "subject", sub in jwt = user + domain id
|
||||
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // user id
|
||||
DomainId string `protobuf:"bytes,3,opt,name=domain_id,json=domainId,proto3" json:"domain_id,omitempty"` // domain id
|
||||
}
|
||||
|
||||
func (x *AuthNRes) Reset() {
|
||||
*x = AuthNRes{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AuthNRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthNRes) ProtoMessage() {}
|
||||
|
||||
func (x *AuthNRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AuthNRes.ProtoReflect.Descriptor instead.
|
||||
func (*AuthNRes) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetUserId() string {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetDomainId() string {
|
||||
if x != nil {
|
||||
return x.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type IssueReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
Type uint32 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func (x *IssueReq) Reset() {
|
||||
*x = IssueReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *IssueReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*IssueReq) ProtoMessage() {}
|
||||
|
||||
func (x *IssueReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use IssueReq.ProtoReflect.Descriptor instead.
|
||||
func (*IssueReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *IssueReq) GetUserId() string {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *IssueReq) GetType() uint32 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type RefreshReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RefreshToken string `protobuf:"bytes,1,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RefreshReq) Reset() {
|
||||
*x = RefreshReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RefreshReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RefreshReq) ProtoMessage() {}
|
||||
|
||||
func (x *RefreshReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RefreshReq.ProtoReflect.Descriptor instead.
|
||||
func (*RefreshReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *RefreshReq) GetRefreshToken() string {
|
||||
if x != nil {
|
||||
return x.RefreshToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AuthZReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"` // Domain
|
||||
SubjectType string `protobuf:"bytes,2,opt,name=subject_type,json=subjectType,proto3" json:"subject_type,omitempty"` // Thing or User
|
||||
SubjectKind string `protobuf:"bytes,3,opt,name=subject_kind,json=subjectKind,proto3" json:"subject_kind,omitempty"` // ID or Token
|
||||
SubjectRelation string `protobuf:"bytes,4,opt,name=subject_relation,json=subjectRelation,proto3" json:"subject_relation,omitempty"` // Subject relation
|
||||
Subject string `protobuf:"bytes,5,opt,name=subject,proto3" json:"subject,omitempty"` // Subject value (id or token, depending on kind)
|
||||
Relation string `protobuf:"bytes,6,opt,name=relation,proto3" json:"relation,omitempty"` // Relation to filter
|
||||
Permission string `protobuf:"bytes,7,opt,name=permission,proto3" json:"permission,omitempty"` // Action
|
||||
Object string `protobuf:"bytes,8,opt,name=object,proto3" json:"object,omitempty"` // Object ID
|
||||
ObjectType string `protobuf:"bytes,9,opt,name=object_type,json=objectType,proto3" json:"object_type,omitempty"` // Thing, User, Group
|
||||
}
|
||||
|
||||
func (x *AuthZReq) Reset() {
|
||||
*x = AuthZReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AuthZReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthZReq) ProtoMessage() {}
|
||||
|
||||
func (x *AuthZReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AuthZReq.ProtoReflect.Descriptor instead.
|
||||
func (*AuthZReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetDomain() string {
|
||||
if x != nil {
|
||||
return x.Domain
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetSubjectType() string {
|
||||
if x != nil {
|
||||
return x.SubjectType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetSubjectKind() string {
|
||||
if x != nil {
|
||||
return x.SubjectKind
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetSubjectRelation() string {
|
||||
if x != nil {
|
||||
return x.SubjectRelation
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetSubject() string {
|
||||
if x != nil {
|
||||
return x.Subject
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetRelation() string {
|
||||
if x != nil {
|
||||
return x.Relation
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetPermission() string {
|
||||
if x != nil {
|
||||
return x.Permission
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetObject() string {
|
||||
if x != nil {
|
||||
return x.Object
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *AuthZReq) GetObjectType() string {
|
||||
if x != nil {
|
||||
return x.ObjectType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type AuthZRes struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AuthZRes) Reset() {
|
||||
*x = AuthZRes{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AuthZRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AuthZRes) ProtoMessage() {}
|
||||
|
||||
func (x *AuthZRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AuthZRes.ProtoReflect.Descriptor instead.
|
||||
func (*AuthZRes) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *AuthZRes) GetAuthorized() bool {
|
||||
if x != nil {
|
||||
return x.Authorized
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *AuthZRes) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DeleteUserRes struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Deleted bool `protobuf:"varint,1,opt,name=deleted,proto3" json:"deleted,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DeleteUserRes) Reset() {
|
||||
*x = DeleteUserRes{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DeleteUserRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteUserRes) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteUserRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DeleteUserRes.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteUserRes) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *DeleteUserRes) GetDeleted() bool {
|
||||
if x != nil {
|
||||
return x.Deleted
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type DeleteUserReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DeleteUserReq) Reset() {
|
||||
*x = DeleteUserReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DeleteUserReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteUserReq) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteUserReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DeleteUserReq.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteUserReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *DeleteUserReq) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ThingsAuthzReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
|
||||
ThingId string `protobuf:"bytes,2,opt,name=thing_id,json=thingId,proto3" json:"thing_id,omitempty"`
|
||||
ThingKey string `protobuf:"bytes,3,opt,name=thing_key,json=thingKey,proto3" json:"thing_key,omitempty"`
|
||||
Permission string `protobuf:"bytes,4,opt,name=permission,proto3" json:"permission,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzReq) Reset() {
|
||||
*x = ThingsAuthzReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ThingsAuthzReq) ProtoMessage() {}
|
||||
|
||||
func (x *ThingsAuthzReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ThingsAuthzReq.ProtoReflect.Descriptor instead.
|
||||
func (*ThingsAuthzReq) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzReq) GetChannelId() string {
|
||||
if x != nil {
|
||||
return x.ChannelId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzReq) GetThingId() string {
|
||||
if x != nil {
|
||||
return x.ThingId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzReq) GetThingKey() string {
|
||||
if x != nil {
|
||||
return x.ThingKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzReq) GetPermission() string {
|
||||
if x != nil {
|
||||
return x.Permission
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ThingsAuthzRes struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzRes) Reset() {
|
||||
*x = ThingsAuthzRes{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_auth_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ThingsAuthzRes) ProtoMessage() {}
|
||||
|
||||
func (x *ThingsAuthzRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_auth_proto_msgTypes[10]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ThingsAuthzRes.ProtoReflect.Descriptor instead.
|
||||
func (*ThingsAuthzRes) Descriptor() ([]byte, []int) {
|
||||
return file_auth_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzRes) GetAuthorized() bool {
|
||||
if x != nil {
|
||||
return x.Authorized
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ThingsAuthzRes) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_auth_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_auth_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x6d, 0x61,
|
||||
0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x22, 0x87, 0x01, 0x0a, 0x05, 0x54, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x28, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
|
||||
0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c,
|
||||
0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x88, 0x01, 0x01, 0x12,
|
||||
0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65,
|
||||
0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x22, 0x20, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x4e, 0x52, 0x65, 0x71, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x50, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x4e, 0x52, 0x65, 0x73,
|
||||
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x6f, 0x6d,
|
||||
0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0x37, 0x0a, 0x08, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52,
|
||||
0x65, 0x71, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22,
|
||||
0x31, 0x0a, 0x0a, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x12, 0x23, 0x0a,
|
||||
0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x22, 0xa2, 0x02, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x5a, 0x52, 0x65, 0x71, 0x12,
|
||||
0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73,
|
||||
0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75,
|
||||
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0b, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x29, 0x0a,
|
||||
0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a,
|
||||
0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a,
|
||||
0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x5a,
|
||||
0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
|
||||
0x7a, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x02, 0x69, 0x64, 0x22, 0x29, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65,
|
||||
0x72, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0x1f,
|
||||
0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22,
|
||||
0x87, 0x01, 0x0a, 0x0e, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x52,
|
||||
0x65, 0x71, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49,
|
||||
0x64, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72,
|
||||
0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70,
|
||||
0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x40, 0x0a, 0x0e, 0x54, 0x68, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x61,
|
||||
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0x56, 0x0a, 0x0d, 0x54,
|
||||
0x68, 0x69, 0x6e, 0x67, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x09,
|
||||
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69,
|
||||
0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x41, 0x75, 0x74,
|
||||
0x68, 0x7a, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61,
|
||||
0x6c, 0x61, 0x2e, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x52, 0x65,
|
||||
0x73, 0x22, 0x00, 0x32, 0x7a, 0x0a, 0x0c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, 0x14, 0x2e, 0x6d,
|
||||
0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x52,
|
||||
0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e,
|
||||
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x72, 0x65,
|
||||
0x73, 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e,
|
||||
0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x67,
|
||||
0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x00, 0x32,
|
||||
0x86, 0x01, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x39, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x2e, 0x6d,
|
||||
0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x5a, 0x52,
|
||||
0x65, 0x71, 0x1a, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e,
|
||||
0x41, 0x75, 0x74, 0x68, 0x5a, 0x52, 0x65, 0x73, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x0c, 0x41, 0x75,
|
||||
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x6d, 0x61, 0x67,
|
||||
0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4e, 0x52, 0x65, 0x71,
|
||||
0x1a, 0x14, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x41, 0x75,
|
||||
0x74, 0x68, 0x4e, 0x52, 0x65, 0x73, 0x22, 0x00, 0x32, 0x61, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x44, 0x65,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x46, 0x72, 0x6f, 0x6d, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x73, 0x12, 0x19, 0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61,
|
||||
0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x19,
|
||||
0x2e, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x2e, 0x44, 0x65, 0x6c, 0x65,
|
||||
0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e,
|
||||
0x2f, 0x6d, 0x61, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_auth_proto_rawDescOnce sync.Once
|
||||
file_auth_proto_rawDescData = file_auth_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_auth_proto_rawDescGZIP() []byte {
|
||||
file_auth_proto_rawDescOnce.Do(func() {
|
||||
file_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_auth_proto_rawDescData)
|
||||
})
|
||||
return file_auth_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
|
||||
var file_auth_proto_goTypes = []any{
|
||||
(*Token)(nil), // 0: magistrala.Token
|
||||
(*AuthNReq)(nil), // 1: magistrala.AuthNReq
|
||||
(*AuthNRes)(nil), // 2: magistrala.AuthNRes
|
||||
(*IssueReq)(nil), // 3: magistrala.IssueReq
|
||||
(*RefreshReq)(nil), // 4: magistrala.RefreshReq
|
||||
(*AuthZReq)(nil), // 5: magistrala.AuthZReq
|
||||
(*AuthZRes)(nil), // 6: magistrala.AuthZRes
|
||||
(*DeleteUserRes)(nil), // 7: magistrala.DeleteUserRes
|
||||
(*DeleteUserReq)(nil), // 8: magistrala.DeleteUserReq
|
||||
(*ThingsAuthzReq)(nil), // 9: magistrala.ThingsAuthzReq
|
||||
(*ThingsAuthzRes)(nil), // 10: magistrala.ThingsAuthzRes
|
||||
}
|
||||
var file_auth_proto_depIdxs = []int32{
|
||||
9, // 0: magistrala.ThingsService.Authorize:input_type -> magistrala.ThingsAuthzReq
|
||||
3, // 1: magistrala.TokenService.Issue:input_type -> magistrala.IssueReq
|
||||
4, // 2: magistrala.TokenService.Refresh:input_type -> magistrala.RefreshReq
|
||||
5, // 3: magistrala.AuthService.Authorize:input_type -> magistrala.AuthZReq
|
||||
1, // 4: magistrala.AuthService.Authenticate:input_type -> magistrala.AuthNReq
|
||||
8, // 5: magistrala.DomainsService.DeleteUserFromDomains:input_type -> magistrala.DeleteUserReq
|
||||
10, // 6: magistrala.ThingsService.Authorize:output_type -> magistrala.ThingsAuthzRes
|
||||
0, // 7: magistrala.TokenService.Issue:output_type -> magistrala.Token
|
||||
0, // 8: magistrala.TokenService.Refresh:output_type -> magistrala.Token
|
||||
6, // 9: magistrala.AuthService.Authorize:output_type -> magistrala.AuthZRes
|
||||
2, // 10: magistrala.AuthService.Authenticate:output_type -> magistrala.AuthNRes
|
||||
7, // 11: magistrala.DomainsService.DeleteUserFromDomains:output_type -> magistrala.DeleteUserRes
|
||||
6, // [6:12] is the sub-list for method output_type
|
||||
0, // [0:6] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_auth_proto_init() }
|
||||
func file_auth_proto_init() {
|
||||
if File_auth_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_auth_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*Token); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*AuthNReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*AuthNRes); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*IssueReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*RefreshReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*AuthZReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*AuthZRes); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*DeleteUserRes); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[8].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*DeleteUserReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[9].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ThingsAuthzReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[10].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ThingsAuthzRes); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_auth_proto_msgTypes[0].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_auth_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 11,
|
||||
NumExtensions: 0,
|
||||
NumServices: 4,
|
||||
},
|
||||
GoTypes: file_auth_proto_goTypes,
|
||||
DependencyIndexes: file_auth_proto_depIdxs,
|
||||
MessageInfos: file_auth_proto_msgTypes,
|
||||
}.Build()
|
||||
File_auth_proto = out.File
|
||||
file_auth_proto_rawDesc = nil
|
||||
file_auth_proto_goTypes = nil
|
||||
file_auth_proto_depIdxs = nil
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package magistrala;
|
||||
option go_package = "./magistrala";
|
||||
|
||||
// ThingsService is a service that provides things authorization functionalities
|
||||
// for magistrala services.
|
||||
service ThingsService {
|
||||
// Authorize checks if the thing is authorized to perform
|
||||
// the action on the channel.
|
||||
rpc Authorize(ThingsAuthzReq) returns (ThingsAuthzRes) {}
|
||||
}
|
||||
|
||||
service TokenService {
|
||||
rpc Issue(IssueReq) returns (Token) {}
|
||||
rpc Refresh(RefreshReq) returns (Token) {}
|
||||
}
|
||||
|
||||
// AuthService is a service that provides authentication and authorization
|
||||
// functionalities for magistrala services.
|
||||
service AuthService {
|
||||
rpc Authorize(AuthZReq) returns (AuthZRes) {}
|
||||
rpc Authenticate(AuthNReq) returns (AuthNRes) {}
|
||||
}
|
||||
|
||||
// DomainsService is a service that provides access to domains
|
||||
// functionalities for magistrala services.
|
||||
service DomainsService {
|
||||
rpc DeleteUserFromDomains(DeleteUserReq) returns (DeleteUserRes) {}
|
||||
}
|
||||
|
||||
// If a token is not carrying any information itself, the type
|
||||
// field can be used to determine how to validate the token.
|
||||
// Also, different tokens can be encoded in different ways.
|
||||
message Token {
|
||||
string access_token = 1;
|
||||
optional string refresh_token = 2;
|
||||
string access_type = 3;
|
||||
}
|
||||
|
||||
message AuthNReq {
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
message AuthNRes {
|
||||
string id = 1; // change "id" to "subject", sub in jwt = user + domain id
|
||||
string user_id = 2; // user id
|
||||
string domain_id = 3; // domain id
|
||||
}
|
||||
|
||||
message IssueReq {
|
||||
string user_id = 1;
|
||||
uint32 type = 2;
|
||||
}
|
||||
|
||||
message RefreshReq {
|
||||
string refresh_token = 1;
|
||||
}
|
||||
|
||||
message AuthZReq {
|
||||
string domain = 1; // Domain
|
||||
string subject_type = 2; // Thing or User
|
||||
string subject_kind = 3; // ID or Token
|
||||
string subject_relation = 4; // Subject relation
|
||||
string subject = 5; // Subject value (id or token, depending on kind)
|
||||
string relation = 6; // Relation to filter
|
||||
string permission = 7; // Action
|
||||
string object = 8; // Object ID
|
||||
string object_type = 9; // Thing, User, Group
|
||||
}
|
||||
|
||||
message AuthZRes {
|
||||
bool authorized = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
message DeleteUserRes {
|
||||
bool deleted = 1;
|
||||
}
|
||||
|
||||
message DeleteUserReq {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message ThingsAuthzReq {
|
||||
string channel_id = 1;
|
||||
string thing_id = 2;
|
||||
string thing_key = 3;
|
||||
string permission = 4;
|
||||
}
|
||||
|
||||
message ThingsAuthzRes {
|
||||
bool authorized = 1;
|
||||
string id = 2;
|
||||
}
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# Auth - Authentication and Authorization service
|
||||
|
||||
Auth service provides authentication features as an API for managing authentication keys as well as administering groups of entities - `things` and `users`.
|
||||
Auth service provides authentication features as an API for managing authentication keys as well as administering groups of entities - `clients` and `users`.
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -25,7 +25,7 @@ Authentication keys are represented and distributed by the corresponding [JWT](j
|
||||
|
||||
User keys are issued when user logs in. Each user request (other than `registration` and `login`) contains user key that is used to authenticate the user.
|
||||
|
||||
API keys are similar to the User keys. The main difference is that API keys have configurable expiration time. If no time is set, the key will never expire. For that reason, API keys are _the only key type that can be revoked_. This also means that, despite being used as a JWT, it requires a query to the database to validate the API key. The user with API key can perform all the same actions as the user with login key (can act on behalf of the user for Thing, Channel, or user profile management), _except issuing new API keys_.
|
||||
API keys are similar to the User keys. The main difference is that API keys have configurable expiration time. If no time is set, the key will never expire. For that reason, API keys are _the only key type that can be revoked_. This also means that, despite being used as a JWT, it requires a query to the database to validate the API key. The user with API key can perform all the same actions as the user with login key (can act on behalf of the user for Client, Channel, or user profile management), _except issuing new API keys_.
|
||||
|
||||
Recovery key is the password recovery key. It's short-lived token used for password recovery process.
|
||||
|
||||
@@ -40,7 +40,7 @@ The following actions are supported:
|
||||
|
||||
## Domains
|
||||
|
||||
Domains are used to group users and things. Each domain has a unique alias that is used to identify the domain. Domains are used to group users and their entities.
|
||||
Domains are used to group users and clients. Each domain has a unique alias that is used to identify the domain. Domains are used to group users and their entities.
|
||||
|
||||
Domain consists of the following fields:
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
grpcAuthV1 "github.com/absmach/magistrala/internal/grpc/auth/v1"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const authSvcName = "magistrala.AuthService"
|
||||
const authSvcName = "auth.v1.AuthService"
|
||||
|
||||
type authGrpcClient struct {
|
||||
authenticate endpoint.Endpoint
|
||||
@@ -22,10 +22,10 @@ type authGrpcClient struct {
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
var _ magistrala.AuthServiceClient = (*authGrpcClient)(nil)
|
||||
var _ grpcAuthV1.AuthServiceClient = (*authGrpcClient)(nil)
|
||||
|
||||
// NewAuthClient returns new auth gRPC client instance.
|
||||
func NewAuthClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.AuthServiceClient {
|
||||
func NewAuthClient(conn *grpc.ClientConn, timeout time.Duration) grpcAuthV1.AuthServiceClient {
|
||||
return &authGrpcClient{
|
||||
authenticate: kitgrpc.NewClient(
|
||||
conn,
|
||||
@@ -33,7 +33,7 @@ func NewAuthClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.Auth
|
||||
"Authenticate",
|
||||
encodeIdentifyRequest,
|
||||
decodeIdentifyResponse,
|
||||
magistrala.AuthNRes{},
|
||||
grpcAuthV1.AuthNRes{},
|
||||
).Endpoint(),
|
||||
authorize: kitgrpc.NewClient(
|
||||
conn,
|
||||
@@ -41,35 +41,35 @@ func NewAuthClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.Auth
|
||||
"Authorize",
|
||||
encodeAuthorizeRequest,
|
||||
decodeAuthorizeResponse,
|
||||
magistrala.AuthZRes{},
|
||||
grpcAuthV1.AuthZRes{},
|
||||
).Endpoint(),
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func (client authGrpcClient) Authenticate(ctx context.Context, token *magistrala.AuthNReq, _ ...grpc.CallOption) (*magistrala.AuthNRes, error) {
|
||||
func (client authGrpcClient) Authenticate(ctx context.Context, token *grpcAuthV1.AuthNReq, _ ...grpc.CallOption) (*grpcAuthV1.AuthNRes, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.authenticate(ctx, authenticateReq{token: token.GetToken()})
|
||||
if err != nil {
|
||||
return &magistrala.AuthNRes{}, grpcapi.DecodeError(err)
|
||||
return &grpcAuthV1.AuthNRes{}, grpcapi.DecodeError(err)
|
||||
}
|
||||
ir := res.(authenticateRes)
|
||||
return &magistrala.AuthNRes{Id: ir.id, UserId: ir.userID, DomainId: ir.domainID}, nil
|
||||
return &grpcAuthV1.AuthNRes{Id: ir.id, UserId: ir.userID, DomainId: ir.domainID}, nil
|
||||
}
|
||||
|
||||
func encodeIdentifyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(authenticateReq)
|
||||
return &magistrala.AuthNReq{Token: req.token}, nil
|
||||
return &grpcAuthV1.AuthNReq{Token: req.token}, nil
|
||||
}
|
||||
|
||||
func decodeIdentifyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.AuthNRes)
|
||||
res := grpcRes.(*grpcAuthV1.AuthNRes)
|
||||
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), domainID: res.GetDomainId()}, nil
|
||||
}
|
||||
|
||||
func (client authGrpcClient) Authorize(ctx context.Context, req *magistrala.AuthZReq, _ ...grpc.CallOption) (r *magistrala.AuthZRes, err error) {
|
||||
func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq, _ ...grpc.CallOption) (r *grpcAuthV1.AuthZRes, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
@@ -84,21 +84,21 @@ func (client authGrpcClient) Authorize(ctx context.Context, req *magistrala.Auth
|
||||
Object: req.GetObject(),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.AuthZRes{}, grpcapi.DecodeError(err)
|
||||
return &grpcAuthV1.AuthZRes{}, grpcapi.DecodeError(err)
|
||||
}
|
||||
|
||||
ar := res.(authorizeRes)
|
||||
return &magistrala.AuthZRes{Authorized: ar.authorized, Id: ar.id}, nil
|
||||
return &grpcAuthV1.AuthZRes{Authorized: ar.authorized, Id: ar.id}, nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*magistrala.AuthZRes)
|
||||
res := grpcRes.(*grpcAuthV1.AuthZRes)
|
||||
return authorizeRes{authorized: res.Authorized, id: res.Id}, nil
|
||||
}
|
||||
|
||||
func encodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(authReq)
|
||||
return &magistrala.AuthZReq{
|
||||
return &grpcAuthV1.AuthZReq{
|
||||
Domain: req.Domain,
|
||||
SubjectType: req.SubjectType,
|
||||
Subject: req.Subject,
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc/auth"
|
||||
grpcAuthV1 "github.com/absmach/magistrala/internal/grpc/auth/v1"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
@@ -28,7 +28,7 @@ const (
|
||||
secret = "secret"
|
||||
email = "test@example.com"
|
||||
id = "testID"
|
||||
thingsType = "things"
|
||||
clientsType = "clients"
|
||||
usersType = "users"
|
||||
description = "Description"
|
||||
groupName = "mgx"
|
||||
@@ -52,7 +52,7 @@ var (
|
||||
func startGRPCServer(svc auth.Service, port int) *grpc.Server {
|
||||
listener, _ := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
server := grpc.NewServer()
|
||||
magistrala.RegisterAuthServiceServer(server, grpcapi.NewAuthServer(svc))
|
||||
grpcAuthV1.RegisterAuthServiceServer(server, grpcapi.NewAuthServer(svc))
|
||||
go func() {
|
||||
err := server.Serve(listener)
|
||||
assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating auth server %s"`, err))
|
||||
@@ -63,40 +63,41 @@ func startGRPCServer(svc auth.Service, port int) *grpc.Server {
|
||||
|
||||
func TestIdentify(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
defer conn.Close()
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
idt *magistrala.AuthNRes
|
||||
idt *grpcAuthV1.AuthNRes
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "authenticate user with valid user token",
|
||||
token: validToken,
|
||||
idt: &magistrala.AuthNRes{Id: id, UserId: email, DomainId: domainID},
|
||||
idt: &grpcAuthV1.AuthNRes{Id: id, UserId: email, DomainId: domainID},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with invalid user token",
|
||||
token: "invalid",
|
||||
idt: &magistrala.AuthNRes{},
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with empty token",
|
||||
token: "",
|
||||
idt: &magistrala.AuthNRes{},
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
err: apiutil.ErrBearerToken,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
svcCall := svc.On("Identify", mock.Anything, mock.Anything, mock.Anything).Return(auth.Key{Subject: id, User: email, Domain: domainID}, tc.svcErr)
|
||||
idt, err := grpcClient.Authenticate(context.Background(), &magistrala.AuthNReq{Token: tc.token})
|
||||
idt, err := grpcClient.Authenticate(context.Background(), &grpcAuthV1.AuthNReq{Token: tc.token})
|
||||
if idt != nil {
|
||||
assert.Equal(t, tc.idt, idt, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.idt, idt))
|
||||
}
|
||||
@@ -107,20 +108,21 @@ func TestIdentify(t *testing.T) {
|
||||
|
||||
func TestAuthorize(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
defer conn.Close()
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
authRequest *magistrala.AuthZReq
|
||||
authResponse *magistrala.AuthZRes
|
||||
authRequest *grpcAuthV1.AuthZReq
|
||||
authResponse *grpcAuthV1.AuthZRes
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "authorize user with authorized token",
|
||||
token: validToken,
|
||||
authRequest: &magistrala.AuthZReq{
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
@@ -128,13 +130,13 @@ func TestAuthorize(t *testing.T) {
|
||||
Relation: memberRelation,
|
||||
Permission: adminpermission,
|
||||
},
|
||||
authResponse: &magistrala.AuthZRes{Authorized: true},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with unauthorized token",
|
||||
token: inValidToken,
|
||||
authRequest: &magistrala.AuthZReq{
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
@@ -142,13 +144,13 @@ func TestAuthorize(t *testing.T) {
|
||||
Relation: memberRelation,
|
||||
Permission: adminpermission,
|
||||
},
|
||||
authResponse: &magistrala.AuthZRes{Authorized: false},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty subject",
|
||||
token: validToken,
|
||||
authRequest: &magistrala.AuthZReq{
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
Subject: "",
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
@@ -156,13 +158,13 @@ func TestAuthorize(t *testing.T) {
|
||||
Relation: memberRelation,
|
||||
Permission: adminpermission,
|
||||
},
|
||||
authResponse: &magistrala.AuthZRes{Authorized: false},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicySub,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty subject type",
|
||||
token: validToken,
|
||||
authRequest: &magistrala.AuthZReq{
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
Subject: id,
|
||||
SubjectType: "",
|
||||
Object: authoritiesObj,
|
||||
@@ -170,13 +172,13 @@ func TestAuthorize(t *testing.T) {
|
||||
Relation: memberRelation,
|
||||
Permission: adminpermission,
|
||||
},
|
||||
authResponse: &magistrala.AuthZRes{Authorized: false},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicySub,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty object",
|
||||
token: validToken,
|
||||
authRequest: &magistrala.AuthZReq{
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: "",
|
||||
@@ -184,13 +186,13 @@ func TestAuthorize(t *testing.T) {
|
||||
Relation: memberRelation,
|
||||
Permission: adminpermission,
|
||||
},
|
||||
authResponse: &magistrala.AuthZRes{Authorized: false},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicyObj,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty object type",
|
||||
token: validToken,
|
||||
authRequest: &magistrala.AuthZReq{
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
@@ -198,13 +200,13 @@ func TestAuthorize(t *testing.T) {
|
||||
Relation: memberRelation,
|
||||
Permission: adminpermission,
|
||||
},
|
||||
authResponse: &magistrala.AuthZRes{Authorized: false},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicyObj,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty permission",
|
||||
token: validToken,
|
||||
authRequest: &magistrala.AuthZReq{
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
@@ -212,7 +214,7 @@ func TestAuthorize(t *testing.T) {
|
||||
Relation: memberRelation,
|
||||
Permission: "",
|
||||
},
|
||||
authResponse: &magistrala.AuthZRes{Authorized: false},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMalformedPolicyPer,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,22 +6,22 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
grpcAuthV1 "github.com/absmach/magistrala/internal/grpc/auth/v1"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
)
|
||||
|
||||
var _ magistrala.AuthServiceServer = (*authGrpcServer)(nil)
|
||||
var _ grpcAuthV1.AuthServiceServer = (*authGrpcServer)(nil)
|
||||
|
||||
type authGrpcServer struct {
|
||||
magistrala.UnimplementedAuthServiceServer
|
||||
grpcAuthV1.UnimplementedAuthServiceServer
|
||||
authorize kitgrpc.Handler
|
||||
authenticate kitgrpc.Handler
|
||||
}
|
||||
|
||||
// NewAuthServer returns new AuthnServiceServer instance.
|
||||
func NewAuthServer(svc auth.Service) magistrala.AuthServiceServer {
|
||||
func NewAuthServer(svc auth.Service) grpcAuthV1.AuthServiceServer {
|
||||
return &authGrpcServer{
|
||||
authorize: kitgrpc.NewServer(
|
||||
(authorizeEndpoint(svc)),
|
||||
@@ -37,34 +37,34 @@ func NewAuthServer(svc auth.Service) magistrala.AuthServiceServer {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *authGrpcServer) Authenticate(ctx context.Context, req *magistrala.AuthNReq) (*magistrala.AuthNRes, error) {
|
||||
func (s *authGrpcServer) Authenticate(ctx context.Context, req *grpcAuthV1.AuthNReq) (*grpcAuthV1.AuthNRes, error) {
|
||||
_, res, err := s.authenticate.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, grpcapi.EncodeError(err)
|
||||
}
|
||||
return res.(*magistrala.AuthNRes), nil
|
||||
return res.(*grpcAuthV1.AuthNRes), nil
|
||||
}
|
||||
|
||||
func (s *authGrpcServer) Authorize(ctx context.Context, req *magistrala.AuthZReq) (*magistrala.AuthZRes, error) {
|
||||
func (s *authGrpcServer) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq) (*grpcAuthV1.AuthZRes, error) {
|
||||
_, res, err := s.authorize.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, grpcapi.EncodeError(err)
|
||||
}
|
||||
return res.(*magistrala.AuthZRes), nil
|
||||
return res.(*grpcAuthV1.AuthZRes), nil
|
||||
}
|
||||
|
||||
func decodeAuthenticateRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.AuthNReq)
|
||||
req := grpcReq.(*grpcAuthV1.AuthNReq)
|
||||
return authenticateReq{token: req.GetToken()}, nil
|
||||
}
|
||||
|
||||
func encodeAuthenticateResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(authenticateRes)
|
||||
return &magistrala.AuthNRes{Id: res.id, UserId: res.userID, DomainId: res.domainID}, nil
|
||||
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID, DomainId: res.domainID}, nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.AuthZReq)
|
||||
req := grpcReq.(*grpcAuthV1.AuthZReq)
|
||||
return authReq{
|
||||
Domain: req.GetDomain(),
|
||||
SubjectType: req.GetSubjectType(),
|
||||
@@ -79,5 +79,5 @@ func decodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}
|
||||
|
||||
func encodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(authorizeRes)
|
||||
return &magistrala.AuthZRes{Authorized: res.authorized, Id: res.id}, nil
|
||||
return &grpcAuthV1.AuthZRes{Authorized: res.authorized, Id: res.id}, nil
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
grpcTokenV1 "github.com/absmach/magistrala/internal/grpc/token/v1"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const tokenSvcName = "magistrala.TokenService"
|
||||
const tokenSvcName = "token.v1.TokenService"
|
||||
|
||||
type tokenGrpcClient struct {
|
||||
issue endpoint.Endpoint
|
||||
@@ -23,10 +23,10 @@ type tokenGrpcClient struct {
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
var _ magistrala.TokenServiceClient = (*tokenGrpcClient)(nil)
|
||||
var _ grpcTokenV1.TokenServiceClient = (*tokenGrpcClient)(nil)
|
||||
|
||||
// NewAuthClient returns new auth gRPC client instance.
|
||||
func NewTokenClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.TokenServiceClient {
|
||||
func NewTokenClient(conn *grpc.ClientConn, timeout time.Duration) grpcTokenV1.TokenServiceClient {
|
||||
return &tokenGrpcClient{
|
||||
issue: kitgrpc.NewClient(
|
||||
conn,
|
||||
@@ -34,7 +34,7 @@ func NewTokenClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.Tok
|
||||
"Issue",
|
||||
encodeIssueRequest,
|
||||
decodeIssueResponse,
|
||||
magistrala.Token{},
|
||||
grpcTokenV1.Token{},
|
||||
).Endpoint(),
|
||||
refresh: kitgrpc.NewClient(
|
||||
conn,
|
||||
@@ -42,13 +42,13 @@ func NewTokenClient(conn *grpc.ClientConn, timeout time.Duration) magistrala.Tok
|
||||
"Refresh",
|
||||
encodeRefreshRequest,
|
||||
decodeRefreshResponse,
|
||||
magistrala.Token{},
|
||||
grpcTokenV1.Token{},
|
||||
).Endpoint(),
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func (client tokenGrpcClient) Issue(ctx context.Context, req *magistrala.IssueReq, _ ...grpc.CallOption) (*magistrala.Token, error) {
|
||||
func (client tokenGrpcClient) Issue(ctx context.Context, req *grpcTokenV1.IssueReq, _ ...grpc.CallOption) (*grpcTokenV1.Token, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
@@ -57,14 +57,14 @@ func (client tokenGrpcClient) Issue(ctx context.Context, req *magistrala.IssueRe
|
||||
keyType: auth.KeyType(req.GetType()),
|
||||
})
|
||||
if err != nil {
|
||||
return &magistrala.Token{}, grpcapi.DecodeError(err)
|
||||
return &grpcTokenV1.Token{}, grpcapi.DecodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
return res.(*grpcTokenV1.Token), nil
|
||||
}
|
||||
|
||||
func encodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(issueReq)
|
||||
return &magistrala.IssueReq{
|
||||
return &grpcTokenV1.IssueReq{
|
||||
UserId: req.userID,
|
||||
Type: uint32(req.keyType),
|
||||
}, nil
|
||||
@@ -74,20 +74,20 @@ func decodeIssueResponse(_ context.Context, grpcRes interface{}) (interface{}, e
|
||||
return grpcRes, nil
|
||||
}
|
||||
|
||||
func (client tokenGrpcClient) Refresh(ctx context.Context, req *magistrala.RefreshReq, _ ...grpc.CallOption) (*magistrala.Token, error) {
|
||||
func (client tokenGrpcClient) Refresh(ctx context.Context, req *grpcTokenV1.RefreshReq, _ ...grpc.CallOption) (*grpcTokenV1.Token, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.refresh(ctx, refreshReq{refreshToken: req.GetRefreshToken()})
|
||||
if err != nil {
|
||||
return &magistrala.Token{}, grpcapi.DecodeError(err)
|
||||
return &grpcTokenV1.Token{}, grpcapi.DecodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
return res.(*grpcTokenV1.Token), nil
|
||||
}
|
||||
|
||||
func encodeRefreshRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(refreshReq)
|
||||
return &magistrala.RefreshReq{RefreshToken: req.refreshToken}, nil
|
||||
return &grpcTokenV1.RefreshReq{RefreshToken: req.refreshToken}, nil
|
||||
}
|
||||
|
||||
func decodeRefreshResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc/token"
|
||||
grpcTokenV1 "github.com/absmach/magistrala/internal/grpc/token/v1"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
@@ -24,11 +24,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
port = 8081
|
||||
port = 8082
|
||||
secret = "secret"
|
||||
email = "test@example.com"
|
||||
id = "testID"
|
||||
thingsType = "things"
|
||||
clientsType = "clients"
|
||||
usersType = "users"
|
||||
description = "Description"
|
||||
groupName = "mgx"
|
||||
@@ -52,7 +52,7 @@ var (
|
||||
func startGRPCServer(svc auth.Service, port int) *grpc.Server {
|
||||
listener, _ := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
server := grpc.NewServer()
|
||||
magistrala.RegisterTokenServiceServer(server, grpcapi.NewTokenServer(svc))
|
||||
grpcTokenV1.RegisterTokenServiceServer(server, grpcapi.NewTokenServer(svc))
|
||||
go func() {
|
||||
err := server.Serve(listener)
|
||||
assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating auth server %s"`, err))
|
||||
@@ -63,6 +63,7 @@ func startGRPCServer(svc auth.Service, port int) *grpc.Server {
|
||||
|
||||
func TestIssue(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
defer conn.Close()
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
|
||||
@@ -117,17 +118,16 @@ func TestIssue(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
|
||||
_, err := grpcClient.Issue(context.Background(), &magistrala.IssueReq{UserId: tc.userId, Type: uint32(tc.kind)})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
})
|
||||
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
|
||||
_, err := grpcClient.Issue(context.Background(), &grpcTokenV1.IssueReq{UserId: tc.userId, Type: uint32(tc.kind)})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefresh(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
defer conn.Close()
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
|
||||
@@ -161,11 +161,9 @@ func TestRefresh(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
|
||||
_, err := grpcClient.Refresh(context.Background(), &magistrala.RefreshReq{RefreshToken: tc.token})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
})
|
||||
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
|
||||
_, err := grpcClient.Refresh(context.Background(), &grpcTokenV1.RefreshReq{RefreshToken: tc.token})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,22 +6,22 @@ package token
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
grpcTokenV1 "github.com/absmach/magistrala/internal/grpc/token/v1"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
)
|
||||
|
||||
var _ magistrala.TokenServiceServer = (*tokenGrpcServer)(nil)
|
||||
var _ grpcTokenV1.TokenServiceServer = (*tokenGrpcServer)(nil)
|
||||
|
||||
type tokenGrpcServer struct {
|
||||
magistrala.UnimplementedTokenServiceServer
|
||||
grpcTokenV1.UnimplementedTokenServiceServer
|
||||
issue kitgrpc.Handler
|
||||
refresh kitgrpc.Handler
|
||||
}
|
||||
|
||||
// NewAuthServer returns new AuthnServiceServer instance.
|
||||
func NewTokenServer(svc auth.Service) magistrala.TokenServiceServer {
|
||||
func NewTokenServer(svc auth.Service) grpcTokenV1.TokenServiceServer {
|
||||
return &tokenGrpcServer{
|
||||
issue: kitgrpc.NewServer(
|
||||
(issueEndpoint(svc)),
|
||||
@@ -36,24 +36,24 @@ func NewTokenServer(svc auth.Service) magistrala.TokenServiceServer {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tokenGrpcServer) Issue(ctx context.Context, req *magistrala.IssueReq) (*magistrala.Token, error) {
|
||||
func (s *tokenGrpcServer) Issue(ctx context.Context, req *grpcTokenV1.IssueReq) (*grpcTokenV1.Token, error) {
|
||||
_, res, err := s.issue.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, grpcapi.EncodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
return res.(*grpcTokenV1.Token), nil
|
||||
}
|
||||
|
||||
func (s *tokenGrpcServer) Refresh(ctx context.Context, req *magistrala.RefreshReq) (*magistrala.Token, error) {
|
||||
func (s *tokenGrpcServer) Refresh(ctx context.Context, req *grpcTokenV1.RefreshReq) (*grpcTokenV1.Token, error) {
|
||||
_, res, err := s.refresh.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, grpcapi.EncodeError(err)
|
||||
}
|
||||
return res.(*magistrala.Token), nil
|
||||
return res.(*grpcTokenV1.Token), nil
|
||||
}
|
||||
|
||||
func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.IssueReq)
|
||||
req := grpcReq.(*grpcTokenV1.IssueReq)
|
||||
return issueReq{
|
||||
userID: req.GetUserId(),
|
||||
keyType: auth.KeyType(req.GetType()),
|
||||
@@ -61,14 +61,14 @@ func decodeIssueRequest(_ context.Context, grpcReq interface{}) (interface{}, er
|
||||
}
|
||||
|
||||
func decodeRefreshRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*magistrala.RefreshReq)
|
||||
req := grpcReq.(*grpcTokenV1.RefreshReq)
|
||||
return refreshReq{refreshToken: req.GetRefreshToken()}, nil
|
||||
}
|
||||
|
||||
func encodeIssueResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(issueRes)
|
||||
|
||||
return &magistrala.Token{
|
||||
return &grpcTokenV1.Token{
|
||||
AccessToken: res.accessToken,
|
||||
RefreshToken: &res.refreshToken,
|
||||
AccessType: res.accessType,
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
func createDomainEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(createDomainReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := auth.Domain{
|
||||
Name: req.Name,
|
||||
Metadata: req.Metadata,
|
||||
Tags: req.Tags,
|
||||
Alias: req.Alias,
|
||||
}
|
||||
domain, err := svc.CreateDomain(ctx, req.token, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return createDomainRes{domain}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveDomainEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(retrieveDomainRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domain, err := svc.RetrieveDomain(ctx, req.token, req.domainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return retrieveDomainRes{domain}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveDomainPermissionsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(retrieveDomainPermissionsRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions, err := svc.RetrieveDomainPermissions(ctx, req.token, req.domainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return retrieveDomainPermissionsRes{Permissions: permissions}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func updateDomainEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(updateDomainReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var metadata auth.Metadata
|
||||
if req.Metadata != nil {
|
||||
metadata = *req.Metadata
|
||||
}
|
||||
d := auth.DomainReq{
|
||||
Name: req.Name,
|
||||
Metadata: &metadata,
|
||||
Tags: req.Tags,
|
||||
Alias: req.Alias,
|
||||
}
|
||||
domain, err := svc.UpdateDomain(ctx, req.token, req.domainID, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return updateDomainRes{domain}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listDomainsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listDomainsReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
page := auth.Page{
|
||||
Offset: req.offset,
|
||||
Limit: req.limit,
|
||||
Name: req.name,
|
||||
Metadata: req.metadata,
|
||||
Order: req.order,
|
||||
Dir: req.dir,
|
||||
Tag: req.tag,
|
||||
Permission: req.permission,
|
||||
Status: req.status,
|
||||
}
|
||||
dp, err := svc.ListDomains(ctx, req.token, page)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listDomainsRes{dp}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func enableDomainEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(enableDomainReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
enable := auth.EnabledStatus
|
||||
d := auth.DomainReq{
|
||||
Status: &enable,
|
||||
}
|
||||
if _, err := svc.ChangeDomainStatus(ctx, req.token, req.domainID, d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enableDomainRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func disableDomainEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(disableDomainReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
disable := auth.DisabledStatus
|
||||
d := auth.DomainReq{
|
||||
Status: &disable,
|
||||
}
|
||||
if _, err := svc.ChangeDomainStatus(ctx, req.token, req.domainID, d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return disableDomainRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func freezeDomainEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(freezeDomainReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
freeze := auth.FreezeStatus
|
||||
d := auth.DomainReq{
|
||||
Status: &freeze,
|
||||
}
|
||||
if _, err := svc.ChangeDomainStatus(ctx, req.token, req.domainID, d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return freezeDomainRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func assignDomainUsersEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(assignUsersReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := svc.AssignUsers(ctx, req.token, req.domainID, req.UserIDs, req.Relation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return assignUsersRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func unassignDomainUserEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(unassignUserReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := svc.UnassignUser(ctx, req.token, req.domainID, req.UserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return unassignUsersRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listUserDomainsEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listUserDomainsReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
page := auth.Page{
|
||||
Offset: req.offset,
|
||||
Limit: req.limit,
|
||||
Name: req.name,
|
||||
Metadata: req.metadata,
|
||||
Order: req.order,
|
||||
Dir: req.dir,
|
||||
Tag: req.tag,
|
||||
Permission: req.permission,
|
||||
Status: req.status,
|
||||
}
|
||||
dp, err := svc.ListUserDomains(ctx, req.token, req.userID, page)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listUserDomainsRes{dp}, nil
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -69,14 +69,12 @@ func (tr testRequest) make() (*http.Response, error) {
|
||||
|
||||
func newService() (auth.Service, *mocks.KeyRepository) {
|
||||
krepo := new(mocks.KeyRepository)
|
||||
drepo := new(mocks.DomainsRepository)
|
||||
idProvider := uuid.NewMock()
|
||||
pService := new(policymocks.Service)
|
||||
pEvaluator := new(policymocks.Evaluator)
|
||||
|
||||
t := jwt.New([]byte(secret))
|
||||
|
||||
return auth.New(krepo, drepo, idProvider, t, pEvaluator, pService, loginDuration, refreshDuration, invalidDuration), krepo
|
||||
return auth.New(krepo, idProvider, t, pEvaluator, pService, loginDuration, refreshDuration, invalidDuration), krepo
|
||||
}
|
||||
|
||||
func newServer(svc auth.Service) *httptest.Server {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/auth/api/http/domains"
|
||||
"github.com/absmach/magistrala/auth/api/http/keys"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
@@ -19,7 +18,6 @@ func MakeHandler(svc auth.Service, logger *slog.Logger, instanceID string) http.
|
||||
mux := chi.NewRouter()
|
||||
|
||||
mux = keys.MakeHandler(svc, mux, logger)
|
||||
mux = domains.MakeHandler(svc, mux, logger)
|
||||
|
||||
mux.Get("/health", magistrala.Health("auth", instanceID))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
@@ -124,180 +124,3 @@ func (lm *loggingMiddleware) Authorize(ctx context.Context, pr policies.Policy)
|
||||
}(time.Now())
|
||||
return lm.svc.Authorize(ctx, pr)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) CreateDomain(ctx context.Context, token string, d auth.Domain) (do auth.Domain, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("domain",
|
||||
slog.String("id", d.ID),
|
||||
slog.String("name", d.Name),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args := append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Create domain failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Create domain completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.CreateDomain(ctx, token, d)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RetrieveDomain(ctx context.Context, token, id string) (do auth.Domain, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("domain_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Retrieve domain failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Retrieve domain completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.RetrieveDomain(ctx, token, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RetrieveDomainPermissions(ctx context.Context, token, id string) (permissions policies.Permissions, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("domain_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Retrieve domain permissions failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Retrieve domain permissions completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.RetrieveDomainPermissions(ctx, token, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UpdateDomain(ctx context.Context, token, id string, d auth.DomainReq) (do auth.Domain, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("domain",
|
||||
slog.String("id", id),
|
||||
slog.Any("name", d.Name),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Update domain failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Update domain completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.UpdateDomain(ctx, token, id, d)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ChangeDomainStatus(ctx context.Context, token, id string, d auth.DomainReq) (do auth.Domain, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("domain",
|
||||
slog.String("id", id),
|
||||
slog.String("name", do.Name),
|
||||
slog.Any("status", d.Status),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Change domain status failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Change domain status completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.ChangeDomainStatus(ctx, token, id, d)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListDomains(ctx context.Context, token string, page auth.Page) (do auth.DomainsPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("page",
|
||||
slog.Uint64("limit", page.Limit),
|
||||
slog.Uint64("offset", page.Offset),
|
||||
slog.Uint64("total", page.Total),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("List domains failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("List domains completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.ListDomains(ctx, token, page)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) AssignUsers(ctx context.Context, token, id string, userIds []string, relation string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("domain_id", id),
|
||||
slog.String("relation", relation),
|
||||
slog.Any("user_ids", userIds),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Assign users to domain failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Assign users to domain completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.AssignUsers(ctx, token, id, userIds, relation)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UnassignUser(ctx context.Context, token, id, userID string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("domain_id", id),
|
||||
slog.Any("user_id", userID),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Unassign user from domain failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Unassign user from domain completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.UnassignUser(ctx, token, id, userID)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListUserDomains(ctx context.Context, token, userID string, page auth.Page) (do auth.DomainsPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("user_id", userID),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("List user domains failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("List user domains completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.ListUserDomains(ctx, token, userID, page)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) DeleteUserFromDomains(ctx context.Context, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Delete entity policies failed to complete successfully", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Delete entity policies completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.DeleteUserFromDomains(ctx, id)
|
||||
}
|
||||
|
||||
@@ -74,83 +74,3 @@ func (ms *metricsMiddleware) Authorize(ctx context.Context, pr policies.Policy)
|
||||
}(time.Now())
|
||||
return ms.svc.Authorize(ctx, pr)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) CreateDomain(ctx context.Context, token string, d auth.Domain) (auth.Domain, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "create_domain").Add(1)
|
||||
ms.latency.With("method", "create_domain").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.CreateDomain(ctx, token, d)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) RetrieveDomain(ctx context.Context, token, id string) (auth.Domain, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "retrieve_domain").Add(1)
|
||||
ms.latency.With("method", "retrieve_domain").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.RetrieveDomain(ctx, token, id)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) RetrieveDomainPermissions(ctx context.Context, token, id string) (policies.Permissions, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "retrieve_domain_permissions").Add(1)
|
||||
ms.latency.With("method", "retrieve_domain_permissions").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.RetrieveDomainPermissions(ctx, token, id)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) UpdateDomain(ctx context.Context, token, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "update_domain").Add(1)
|
||||
ms.latency.With("method", "update_domain").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.UpdateDomain(ctx, token, id, d)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ChangeDomainStatus(ctx context.Context, token, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "change_domain_status").Add(1)
|
||||
ms.latency.With("method", "change_domain_status").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ChangeDomainStatus(ctx, token, id, d)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ListDomains(ctx context.Context, token string, page auth.Page) (auth.DomainsPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_domains").Add(1)
|
||||
ms.latency.With("method", "list_domains").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ListDomains(ctx, token, page)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) AssignUsers(ctx context.Context, token, id string, userIds []string, relation string) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "assign_users").Add(1)
|
||||
ms.latency.With("method", "assign_users").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.AssignUsers(ctx, token, id, userIds, relation)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) UnassignUser(ctx context.Context, token, id, userID string) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "unassign_users").Add(1)
|
||||
ms.latency.With("method", "unassign_users").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.UnassignUser(ctx, token, id, userID)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ListUserDomains(ctx context.Context, token, userID string, page auth.Page) (auth.DomainsPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_user_domains").Add(1)
|
||||
ms.latency.With("method", "list_user_domains").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ListUserDomains(ctx, token, userID, page)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) DeleteUserFromDomains(ctx context.Context, id string) error {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "delete_user_from_domains").Add(1)
|
||||
ms.latency.With("method", "delete_user_from_domains").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.DeleteUserFromDomains(ctx, id)
|
||||
}
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/events"
|
||||
"github.com/absmach/magistrala/pkg/events/store"
|
||||
"github.com/absmach/magistrala/pkg/policies"
|
||||
)
|
||||
|
||||
const streamID = "magistrala.auth"
|
||||
|
||||
var _ auth.Service = (*eventStore)(nil)
|
||||
|
||||
type eventStore struct {
|
||||
events.Publisher
|
||||
svc auth.Service
|
||||
}
|
||||
|
||||
// NewEventStoreMiddleware returns wrapper around auth service that sends
|
||||
// events to event store.
|
||||
func NewEventStoreMiddleware(ctx context.Context, svc auth.Service, url string) (auth.Service, error) {
|
||||
publisher, err := store.NewPublisher(ctx, url, streamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &eventStore{
|
||||
svc: svc,
|
||||
Publisher: publisher,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) CreateDomain(ctx context.Context, token string, domain auth.Domain) (auth.Domain, error) {
|
||||
domain, err := es.svc.CreateDomain(ctx, token, domain)
|
||||
if err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
event := createDomainEvent{
|
||||
domain,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
return domain, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) RetrieveDomain(ctx context.Context, token, id string) (auth.Domain, error) {
|
||||
domain, err := es.svc.RetrieveDomain(ctx, token, id)
|
||||
if err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
event := retrieveDomainEvent{
|
||||
domain,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
return domain, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) RetrieveDomainPermissions(ctx context.Context, token, id string) (policies.Permissions, error) {
|
||||
permissions, err := es.svc.RetrieveDomainPermissions(ctx, token, id)
|
||||
if err != nil {
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
event := retrieveDomainPermissionsEvent{
|
||||
domainID: id,
|
||||
permissions: permissions,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) UpdateDomain(ctx context.Context, token, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
domain, err := es.svc.UpdateDomain(ctx, token, id, d)
|
||||
if err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
event := updateDomainEvent{
|
||||
domain,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
return domain, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ChangeDomainStatus(ctx context.Context, token, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
domain, err := es.svc.ChangeDomainStatus(ctx, token, id, d)
|
||||
if err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
event := changeDomainStatusEvent{
|
||||
domainID: id,
|
||||
status: domain.Status,
|
||||
updatedAt: domain.UpdatedAt,
|
||||
updatedBy: domain.UpdatedBy,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return domain, err
|
||||
}
|
||||
|
||||
return domain, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ListDomains(ctx context.Context, token string, p auth.Page) (auth.DomainsPage, error) {
|
||||
dp, err := es.svc.ListDomains(ctx, token, p)
|
||||
if err != nil {
|
||||
return dp, err
|
||||
}
|
||||
|
||||
event := listDomainsEvent{
|
||||
p, dp.Total,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return dp, err
|
||||
}
|
||||
|
||||
return dp, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) AssignUsers(ctx context.Context, token, id string, userIds []string, relation string) error {
|
||||
err := es.svc.AssignUsers(ctx, token, id, userIds, relation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := assignUsersEvent{
|
||||
domainID: id,
|
||||
userIDs: userIds,
|
||||
relation: relation,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventStore) UnassignUser(ctx context.Context, token, id, userID string) error {
|
||||
err := es.svc.UnassignUser(ctx, token, id, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := unassignUsersEvent{
|
||||
domainID: id,
|
||||
userID: userID,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ListUserDomains(ctx context.Context, token, userID string, p auth.Page) (auth.DomainsPage, error) {
|
||||
dp, err := es.svc.ListUserDomains(ctx, token, userID, p)
|
||||
if err != nil {
|
||||
return dp, err
|
||||
}
|
||||
|
||||
event := listUserDomainsEvent{
|
||||
Page: p,
|
||||
userID: userID,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return dp, err
|
||||
}
|
||||
|
||||
return dp, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) Issue(ctx context.Context, token string, key auth.Key) (auth.Token, error) {
|
||||
return es.svc.Issue(ctx, token, key)
|
||||
}
|
||||
|
||||
func (es *eventStore) Revoke(ctx context.Context, token, id string) error {
|
||||
return es.svc.Revoke(ctx, token, id)
|
||||
}
|
||||
|
||||
func (es *eventStore) RetrieveKey(ctx context.Context, token, id string) (auth.Key, error) {
|
||||
return es.svc.RetrieveKey(ctx, token, id)
|
||||
}
|
||||
|
||||
func (es *eventStore) Identify(ctx context.Context, token string) (auth.Key, error) {
|
||||
return es.svc.Identify(ctx, token)
|
||||
}
|
||||
|
||||
func (es *eventStore) Authorize(ctx context.Context, pr policies.Policy) error {
|
||||
return es.svc.Authorize(ctx, pr)
|
||||
}
|
||||
|
||||
func (es *eventStore) DeleteUserFromDomains(ctx context.Context, id string) error {
|
||||
return es.svc.DeleteUserFromDomains(ctx, id)
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
// Code generated by mockery v2.43.2. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
auth "github.com/absmach/magistrala/auth"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// DomainsRepository is an autogenerated mock type for the DomainsRepository type
|
||||
type DomainsRepository struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CheckPolicy provides a mock function with given fields: ctx, pc
|
||||
func (_m *DomainsRepository) CheckPolicy(ctx context.Context, pc auth.Policy) error {
|
||||
ret := _m.Called(ctx, pc)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckPolicy")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, auth.Policy) error); ok {
|
||||
r0 = rf(ctx, pc)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ctx, id
|
||||
func (_m *DomainsRepository) Delete(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Delete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeletePolicies provides a mock function with given fields: ctx, pcs
|
||||
func (_m *DomainsRepository) DeletePolicies(ctx context.Context, pcs ...auth.Policy) error {
|
||||
_va := make([]interface{}, len(pcs))
|
||||
for _i := range pcs {
|
||||
_va[_i] = pcs[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeletePolicies")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, ...auth.Policy) error); ok {
|
||||
r0 = rf(ctx, pcs...)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteUserPolicies provides a mock function with given fields: ctx, id
|
||||
func (_m *DomainsRepository) DeleteUserPolicies(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteUserPolicies")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// ListDomains provides a mock function with given fields: ctx, pm
|
||||
func (_m *DomainsRepository) ListDomains(ctx context.Context, pm auth.Page) (auth.DomainsPage, error) {
|
||||
ret := _m.Called(ctx, pm)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListDomains")
|
||||
}
|
||||
|
||||
var r0 auth.DomainsPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, auth.Page) (auth.DomainsPage, error)); ok {
|
||||
return rf(ctx, pm)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, auth.Page) auth.DomainsPage); ok {
|
||||
r0 = rf(ctx, pm)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.DomainsPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, auth.Page) error); ok {
|
||||
r1 = rf(ctx, pm)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveAllByIDs provides a mock function with given fields: ctx, pm
|
||||
func (_m *DomainsRepository) RetrieveAllByIDs(ctx context.Context, pm auth.Page) (auth.DomainsPage, error) {
|
||||
ret := _m.Called(ctx, pm)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveAllByIDs")
|
||||
}
|
||||
|
||||
var r0 auth.DomainsPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, auth.Page) (auth.DomainsPage, error)); ok {
|
||||
return rf(ctx, pm)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, auth.Page) auth.DomainsPage); ok {
|
||||
r0 = rf(ctx, pm)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.DomainsPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, auth.Page) error); ok {
|
||||
r1 = rf(ctx, pm)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveByID provides a mock function with given fields: ctx, id
|
||||
func (_m *DomainsRepository) RetrieveByID(ctx context.Context, id string) (auth.Domain, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveByID")
|
||||
}
|
||||
|
||||
var r0 auth.Domain
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) (auth.Domain, error)); ok {
|
||||
return rf(ctx, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) auth.Domain); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.Domain)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrievePermissions provides a mock function with given fields: ctx, subject, id
|
||||
func (_m *DomainsRepository) RetrievePermissions(ctx context.Context, subject string, id string) ([]string, error) {
|
||||
ret := _m.Called(ctx, subject, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrievePermissions")
|
||||
}
|
||||
|
||||
var r0 []string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]string, error)); ok {
|
||||
return rf(ctx, subject, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) []string); ok {
|
||||
r0 = rf(ctx, subject, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, subject, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Save provides a mock function with given fields: ctx, d
|
||||
func (_m *DomainsRepository) Save(ctx context.Context, d auth.Domain) (auth.Domain, error) {
|
||||
ret := _m.Called(ctx, d)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Save")
|
||||
}
|
||||
|
||||
var r0 auth.Domain
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, auth.Domain) (auth.Domain, error)); ok {
|
||||
return rf(ctx, d)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, auth.Domain) auth.Domain); ok {
|
||||
r0 = rf(ctx, d)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.Domain)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, auth.Domain) error); ok {
|
||||
r1 = rf(ctx, d)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SavePolicies provides a mock function with given fields: ctx, pcs
|
||||
func (_m *DomainsRepository) SavePolicies(ctx context.Context, pcs ...auth.Policy) error {
|
||||
_va := make([]interface{}, len(pcs))
|
||||
for _i := range pcs {
|
||||
_va[_i] = pcs[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SavePolicies")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, ...auth.Policy) error); ok {
|
||||
r0 = rf(ctx, pcs...)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, id, userID, d
|
||||
func (_m *DomainsRepository) Update(ctx context.Context, id string, userID string, d auth.DomainReq) (auth.Domain, error) {
|
||||
ret := _m.Called(ctx, id, userID, d)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Update")
|
||||
}
|
||||
|
||||
var r0 auth.Domain
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) (auth.Domain, error)); ok {
|
||||
return rf(ctx, id, userID, d)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) auth.Domain); ok {
|
||||
r0 = rf(ctx, id, userID, d)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.Domain)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.DomainReq) error); ok {
|
||||
r1 = rf(ctx, id, userID, d)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewDomainsRepository creates a new instance of DomainsRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewDomainsRepository(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *DomainsRepository {
|
||||
mock := &DomainsRepository{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -19,24 +19,6 @@ type Service struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AssignUsers provides a mock function with given fields: ctx, token, id, userIds, relation
|
||||
func (_m *Service) AssignUsers(ctx context.Context, token string, id string, userIds []string, relation string) error {
|
||||
ret := _m.Called(ctx, token, id, userIds, relation)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AssignUsers")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, []string, string) error); ok {
|
||||
r0 = rf(ctx, token, id, userIds, relation)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Authorize provides a mock function with given fields: ctx, pr
|
||||
func (_m *Service) Authorize(ctx context.Context, pr policies.Policy) error {
|
||||
ret := _m.Called(ctx, pr)
|
||||
@@ -55,80 +37,6 @@ func (_m *Service) Authorize(ctx context.Context, pr policies.Policy) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// ChangeDomainStatus provides a mock function with given fields: ctx, token, id, d
|
||||
func (_m *Service) ChangeDomainStatus(ctx context.Context, token string, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
ret := _m.Called(ctx, token, id, d)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ChangeDomainStatus")
|
||||
}
|
||||
|
||||
var r0 auth.Domain
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) (auth.Domain, error)); ok {
|
||||
return rf(ctx, token, id, d)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) auth.Domain); ok {
|
||||
r0 = rf(ctx, token, id, d)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.Domain)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.DomainReq) error); ok {
|
||||
r1 = rf(ctx, token, id, d)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateDomain provides a mock function with given fields: ctx, token, d
|
||||
func (_m *Service) CreateDomain(ctx context.Context, token string, d auth.Domain) (auth.Domain, error) {
|
||||
ret := _m.Called(ctx, token, d)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CreateDomain")
|
||||
}
|
||||
|
||||
var r0 auth.Domain
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, auth.Domain) (auth.Domain, error)); ok {
|
||||
return rf(ctx, token, d)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, auth.Domain) auth.Domain); ok {
|
||||
r0 = rf(ctx, token, d)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.Domain)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, auth.Domain) error); ok {
|
||||
r1 = rf(ctx, token, d)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteUserFromDomains provides a mock function with given fields: ctx, id
|
||||
func (_m *Service) DeleteUserFromDomains(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteUserFromDomains")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Identify provides a mock function with given fields: ctx, token
|
||||
func (_m *Service) Identify(ctx context.Context, token string) (auth.Key, error) {
|
||||
ret := _m.Called(ctx, token)
|
||||
@@ -185,120 +93,6 @@ func (_m *Service) Issue(ctx context.Context, token string, key auth.Key) (auth.
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListDomains provides a mock function with given fields: ctx, token, page
|
||||
func (_m *Service) ListDomains(ctx context.Context, token string, page auth.Page) (auth.DomainsPage, error) {
|
||||
ret := _m.Called(ctx, token, page)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListDomains")
|
||||
}
|
||||
|
||||
var r0 auth.DomainsPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, auth.Page) (auth.DomainsPage, error)); ok {
|
||||
return rf(ctx, token, page)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, auth.Page) auth.DomainsPage); ok {
|
||||
r0 = rf(ctx, token, page)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.DomainsPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, auth.Page) error); ok {
|
||||
r1 = rf(ctx, token, page)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListUserDomains provides a mock function with given fields: ctx, token, userID, page
|
||||
func (_m *Service) ListUserDomains(ctx context.Context, token string, userID string, page auth.Page) (auth.DomainsPage, error) {
|
||||
ret := _m.Called(ctx, token, userID, page)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListUserDomains")
|
||||
}
|
||||
|
||||
var r0 auth.DomainsPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.Page) (auth.DomainsPage, error)); ok {
|
||||
return rf(ctx, token, userID, page)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.Page) auth.DomainsPage); ok {
|
||||
r0 = rf(ctx, token, userID, page)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.DomainsPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.Page) error); ok {
|
||||
r1 = rf(ctx, token, userID, page)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveDomain provides a mock function with given fields: ctx, token, id
|
||||
func (_m *Service) RetrieveDomain(ctx context.Context, token string, id string) (auth.Domain, error) {
|
||||
ret := _m.Called(ctx, token, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveDomain")
|
||||
}
|
||||
|
||||
var r0 auth.Domain
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) (auth.Domain, error)); ok {
|
||||
return rf(ctx, token, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) auth.Domain); ok {
|
||||
r0 = rf(ctx, token, id)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.Domain)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, token, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveDomainPermissions provides a mock function with given fields: ctx, token, id
|
||||
func (_m *Service) RetrieveDomainPermissions(ctx context.Context, token string, id string) (policies.Permissions, error) {
|
||||
ret := _m.Called(ctx, token, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveDomainPermissions")
|
||||
}
|
||||
|
||||
var r0 policies.Permissions
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) (policies.Permissions, error)); ok {
|
||||
return rf(ctx, token, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) policies.Permissions); ok {
|
||||
r0 = rf(ctx, token, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(policies.Permissions)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, token, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveKey provides a mock function with given fields: ctx, token, id
|
||||
func (_m *Service) RetrieveKey(ctx context.Context, token string, id string) (auth.Key, error) {
|
||||
ret := _m.Called(ctx, token, id)
|
||||
@@ -345,52 +139,6 @@ func (_m *Service) Revoke(ctx context.Context, token string, id string) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// UnassignUser provides a mock function with given fields: ctx, token, id, userID
|
||||
func (_m *Service) UnassignUser(ctx context.Context, token string, id string, userID string) error {
|
||||
ret := _m.Called(ctx, token, id, userID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UnassignUser")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok {
|
||||
r0 = rf(ctx, token, id, userID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateDomain provides a mock function with given fields: ctx, token, id, d
|
||||
func (_m *Service) UpdateDomain(ctx context.Context, token string, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
ret := _m.Called(ctx, token, id, d)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateDomain")
|
||||
}
|
||||
|
||||
var r0 auth.Domain
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) (auth.Domain, error)); ok {
|
||||
return rf(ctx, token, id, d)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, auth.DomainReq) auth.Domain); ok {
|
||||
r0 = rf(ctx, token, id, d)
|
||||
} else {
|
||||
r0 = ret.Get(0).(auth.Domain)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, auth.DomainReq) error); ok {
|
||||
r1 = rf(ctx, token, id, d)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewService(t interface {
|
||||
|
||||
+24
-24
@@ -11,9 +11,9 @@ import (
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
|
||||
magistrala "github.com/absmach/magistrala"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
v1 "github.com/absmach/magistrala/internal/grpc/token/v1"
|
||||
)
|
||||
|
||||
// TokenServiceClient is an autogenerated mock type for the TokenServiceClient type
|
||||
@@ -30,7 +30,7 @@ func (_m *TokenServiceClient) EXPECT() *TokenServiceClient_Expecter {
|
||||
}
|
||||
|
||||
// Issue provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *TokenServiceClient) Issue(ctx context.Context, in *magistrala.IssueReq, opts ...grpc.CallOption) (*magistrala.Token, error) {
|
||||
func (_m *TokenServiceClient) Issue(ctx context.Context, in *v1.IssueReq, opts ...grpc.CallOption) (*v1.Token, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
@@ -44,20 +44,20 @@ func (_m *TokenServiceClient) Issue(ctx context.Context, in *magistrala.IssueReq
|
||||
panic("no return value specified for Issue")
|
||||
}
|
||||
|
||||
var r0 *magistrala.Token
|
||||
var r0 *v1.Token
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *magistrala.IssueReq, ...grpc.CallOption) (*magistrala.Token, error)); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1.IssueReq, ...grpc.CallOption) (*v1.Token, error)); ok {
|
||||
return rf(ctx, in, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *magistrala.IssueReq, ...grpc.CallOption) *magistrala.Token); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1.IssueReq, ...grpc.CallOption) *v1.Token); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*magistrala.Token)
|
||||
r0 = ret.Get(0).(*v1.Token)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *magistrala.IssueReq, ...grpc.CallOption) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1.IssueReq, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -73,14 +73,14 @@ type TokenServiceClient_Issue_Call struct {
|
||||
|
||||
// Issue is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - in *magistrala.IssueReq
|
||||
// - in *v1.IssueReq
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *TokenServiceClient_Expecter) Issue(ctx interface{}, in interface{}, opts ...interface{}) *TokenServiceClient_Issue_Call {
|
||||
return &TokenServiceClient_Issue_Call{Call: _e.mock.On("Issue",
|
||||
append([]interface{}{ctx, in}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *TokenServiceClient_Issue_Call) Run(run func(ctx context.Context, in *magistrala.IssueReq, opts ...grpc.CallOption)) *TokenServiceClient_Issue_Call {
|
||||
func (_c *TokenServiceClient_Issue_Call) Run(run func(ctx context.Context, in *v1.IssueReq, opts ...grpc.CallOption)) *TokenServiceClient_Issue_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
@@ -88,23 +88,23 @@ func (_c *TokenServiceClient_Issue_Call) Run(run func(ctx context.Context, in *m
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*magistrala.IssueReq), variadicArgs...)
|
||||
run(args[0].(context.Context), args[1].(*v1.IssueReq), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *TokenServiceClient_Issue_Call) Return(_a0 *magistrala.Token, _a1 error) *TokenServiceClient_Issue_Call {
|
||||
func (_c *TokenServiceClient_Issue_Call) Return(_a0 *v1.Token, _a1 error) *TokenServiceClient_Issue_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *TokenServiceClient_Issue_Call) RunAndReturn(run func(context.Context, *magistrala.IssueReq, ...grpc.CallOption) (*magistrala.Token, error)) *TokenServiceClient_Issue_Call {
|
||||
func (_c *TokenServiceClient_Issue_Call) RunAndReturn(run func(context.Context, *v1.IssueReq, ...grpc.CallOption) (*v1.Token, error)) *TokenServiceClient_Issue_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Refresh provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *TokenServiceClient) Refresh(ctx context.Context, in *magistrala.RefreshReq, opts ...grpc.CallOption) (*magistrala.Token, error) {
|
||||
func (_m *TokenServiceClient) Refresh(ctx context.Context, in *v1.RefreshReq, opts ...grpc.CallOption) (*v1.Token, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
@@ -118,20 +118,20 @@ func (_m *TokenServiceClient) Refresh(ctx context.Context, in *magistrala.Refres
|
||||
panic("no return value specified for Refresh")
|
||||
}
|
||||
|
||||
var r0 *magistrala.Token
|
||||
var r0 *v1.Token
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *magistrala.RefreshReq, ...grpc.CallOption) (*magistrala.Token, error)); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1.RefreshReq, ...grpc.CallOption) (*v1.Token, error)); ok {
|
||||
return rf(ctx, in, opts...)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *magistrala.RefreshReq, ...grpc.CallOption) *magistrala.Token); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1.RefreshReq, ...grpc.CallOption) *v1.Token); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*magistrala.Token)
|
||||
r0 = ret.Get(0).(*v1.Token)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *magistrala.RefreshReq, ...grpc.CallOption) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1.RefreshReq, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -147,14 +147,14 @@ type TokenServiceClient_Refresh_Call struct {
|
||||
|
||||
// Refresh is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - in *magistrala.RefreshReq
|
||||
// - in *v1.RefreshReq
|
||||
// - opts ...grpc.CallOption
|
||||
func (_e *TokenServiceClient_Expecter) Refresh(ctx interface{}, in interface{}, opts ...interface{}) *TokenServiceClient_Refresh_Call {
|
||||
return &TokenServiceClient_Refresh_Call{Call: _e.mock.On("Refresh",
|
||||
append([]interface{}{ctx, in}, opts...)...)}
|
||||
}
|
||||
|
||||
func (_c *TokenServiceClient_Refresh_Call) Run(run func(ctx context.Context, in *magistrala.RefreshReq, opts ...grpc.CallOption)) *TokenServiceClient_Refresh_Call {
|
||||
func (_c *TokenServiceClient_Refresh_Call) Run(run func(ctx context.Context, in *v1.RefreshReq, opts ...grpc.CallOption)) *TokenServiceClient_Refresh_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
variadicArgs := make([]grpc.CallOption, len(args)-2)
|
||||
for i, a := range args[2:] {
|
||||
@@ -162,17 +162,17 @@ func (_c *TokenServiceClient_Refresh_Call) Run(run func(ctx context.Context, in
|
||||
variadicArgs[i] = a.(grpc.CallOption)
|
||||
}
|
||||
}
|
||||
run(args[0].(context.Context), args[1].(*magistrala.RefreshReq), variadicArgs...)
|
||||
run(args[0].(context.Context), args[1].(*v1.RefreshReq), variadicArgs...)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *TokenServiceClient_Refresh_Call) Return(_a0 *magistrala.Token, _a1 error) *TokenServiceClient_Refresh_Call {
|
||||
func (_c *TokenServiceClient_Refresh_Call) Return(_a0 *v1.Token, _a1 error) *TokenServiceClient_Refresh_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *TokenServiceClient_Refresh_Call) RunAndReturn(run func(context.Context, *magistrala.RefreshReq, ...grpc.CallOption) (*magistrala.Token, error)) *TokenServiceClient_Refresh_Call {
|
||||
func (_c *TokenServiceClient_Refresh_Call) RunAndReturn(run func(context.Context, *v1.RefreshReq, ...grpc.CallOption) (*v1.Token, error)) *TokenServiceClient_Refresh_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,14 @@ func Migration() *migrate.MemoryMigrationSource {
|
||||
`ALTER TABLE domains ALTER COLUMN alias SET NOT NULL`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "auth_3",
|
||||
Up: []string{
|
||||
`DROP TABLE IF EXISTS policies;
|
||||
DROP TABLE IF EXISTS domains;
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+10
-498
@@ -5,7 +5,6 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -24,18 +23,12 @@ var (
|
||||
// ErrExpiry indicates that the token is expired.
|
||||
ErrExpiry = errors.New("token is expired")
|
||||
|
||||
errIssueUser = errors.New("failed to issue new login key")
|
||||
errIssueTmp = errors.New("failed to issue new temporary key")
|
||||
errRevoke = errors.New("failed to remove key")
|
||||
errRetrieve = errors.New("failed to retrieve key data")
|
||||
errIdentify = errors.New("failed to validate token")
|
||||
errPlatform = errors.New("invalid platform id")
|
||||
errCreateDomainPolicy = errors.New("failed to create domain policy")
|
||||
errAddPolicies = errors.New("failed to add policies")
|
||||
errRemovePolicies = errors.New("failed to remove the policies")
|
||||
errRollbackPolicy = errors.New("failed to rollback policy")
|
||||
errRemoveLocalPolicy = errors.New("failed to remove from local policy copy")
|
||||
errRemovePolicyEngine = errors.New("failed to remove from policy engine")
|
||||
errIssueUser = errors.New("failed to issue new login key")
|
||||
errIssueTmp = errors.New("failed to issue new temporary key")
|
||||
errRevoke = errors.New("failed to remove key")
|
||||
errRetrieve = errors.New("failed to retrieve key data")
|
||||
errIdentify = errors.New("failed to validate token")
|
||||
errPlatform = errors.New("invalid platform id")
|
||||
)
|
||||
|
||||
// Authz represents a authorization service. It exposes
|
||||
@@ -82,14 +75,12 @@ type Authn interface {
|
||||
type Service interface {
|
||||
Authn
|
||||
Authz
|
||||
Domains
|
||||
}
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
type service struct {
|
||||
keys KeyRepository
|
||||
domains DomainsRepository
|
||||
idProvider magistrala.IDProvider
|
||||
evaluator policies.Evaluator
|
||||
policysvc policies.Service
|
||||
@@ -100,10 +91,9 @@ type service struct {
|
||||
}
|
||||
|
||||
// New instantiates the auth service implementation.
|
||||
func New(keys KeyRepository, domains DomainsRepository, idp magistrala.IDProvider, tokenizer Tokenizer, policyEvaluator policies.Evaluator, policyService policies.Service, loginDuration, refreshDuration, invitationDuration time.Duration) Service {
|
||||
func New(keys KeyRepository, idp magistrala.IDProvider, tokenizer Tokenizer, policyEvaluator policies.Evaluator, policyService policies.Service, loginDuration, refreshDuration, invitationDuration time.Duration) Service {
|
||||
return &service{
|
||||
tokenizer: tokenizer,
|
||||
domains: domains,
|
||||
keys: keys,
|
||||
idProvider: idp,
|
||||
evaluator: policyEvaluator,
|
||||
@@ -188,7 +178,7 @@ func (svc service) Authorize(ctx context.Context, pr policies.Policy) error {
|
||||
return errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
if key.Subject == "" {
|
||||
if pr.ObjectType == policies.GroupType || pr.ObjectType == policies.ThingType || pr.ObjectType == policies.DomainType {
|
||||
if pr.ObjectType == policies.GroupType || pr.ObjectType == policies.ClientType || pr.ObjectType == policies.DomainType {
|
||||
return svcerr.ErrDomainAuthorization
|
||||
}
|
||||
return svcerr.ErrAuthentication
|
||||
@@ -203,8 +193,8 @@ func (svc service) Authorize(ctx context.Context, pr policies.Policy) error {
|
||||
}
|
||||
|
||||
func (svc service) checkPolicy(ctx context.Context, pr policies.Policy) error {
|
||||
// Domain status is required for if user sent authorization request on things, channels, groups and domains
|
||||
if pr.SubjectType == policies.UserType && (pr.ObjectType == policies.GroupType || pr.ObjectType == policies.ThingType || pr.ObjectType == policies.DomainType) {
|
||||
// Domain status is required for if user sent authorization request on clients, channels, groups and domains
|
||||
if pr.SubjectType == policies.UserType && (pr.ObjectType == policies.GroupType || pr.ObjectType == policies.ClientType || pr.ObjectType == policies.DomainType) {
|
||||
domainID := pr.Domain
|
||||
if domainID == "" {
|
||||
if pr.ObjectType != policies.DomainType {
|
||||
@@ -233,37 +223,6 @@ func (svc service) checkDomain(ctx context.Context, subjectType, subject, domain
|
||||
return svcerr.ErrDomainAuthorization
|
||||
}
|
||||
|
||||
d, err := svc.domains.RetrieveByID(ctx, domainID)
|
||||
if err != nil {
|
||||
return errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
switch d.Status {
|
||||
case EnabledStatus:
|
||||
case DisabledStatus:
|
||||
if err := svc.evaluator.CheckPolicy(ctx, policies.Policy{
|
||||
Subject: subject,
|
||||
SubjectType: subjectType,
|
||||
Permission: policies.AdminPermission,
|
||||
Object: domainID,
|
||||
ObjectType: policies.DomainType,
|
||||
}); err != nil {
|
||||
return svcerr.ErrDomainAuthorization
|
||||
}
|
||||
case FreezeStatus:
|
||||
if err := svc.evaluator.CheckPolicy(ctx, policies.Policy{
|
||||
Subject: subject,
|
||||
SubjectType: subjectType,
|
||||
Permission: policies.AdminPermission,
|
||||
Object: policies.MagistralaObject,
|
||||
ObjectType: policies.PlatformType,
|
||||
}); err != nil {
|
||||
return svcerr.ErrDomainAuthorization
|
||||
}
|
||||
default:
|
||||
return svcerr.ErrDomainAuthorization
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -451,405 +410,6 @@ func SwitchToPermission(relation string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (svc service) CreateDomain(ctx context.Context, token string, d Domain) (do Domain, err error) {
|
||||
key, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
d.CreatedBy = key.User
|
||||
|
||||
domainID, err := svc.idProvider.ID()
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrCreateEntity, err)
|
||||
}
|
||||
d.ID = domainID
|
||||
|
||||
if d.Status != DisabledStatus && d.Status != EnabledStatus {
|
||||
return Domain{}, svcerr.ErrInvalidStatus
|
||||
}
|
||||
|
||||
d.CreatedAt = time.Now()
|
||||
|
||||
if err := svc.createDomainPolicy(ctx, key.User, domainID, policies.AdministratorRelation); err != nil {
|
||||
return Domain{}, errors.Wrap(errCreateDomainPolicy, err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if errRollBack := svc.createDomainPolicyRollback(ctx, key.User, domainID, policies.AdministratorRelation); errRollBack != nil {
|
||||
err = errors.Wrap(err, errors.Wrap(errRollbackPolicy, errRollBack))
|
||||
}
|
||||
}
|
||||
}()
|
||||
dom, err := svc.domains.Save(ctx, d)
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrCreateEntity, err)
|
||||
}
|
||||
|
||||
return dom, nil
|
||||
}
|
||||
|
||||
func (svc service) RetrieveDomain(ctx context.Context, token, id string) (Domain, error) {
|
||||
res, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
domain, err := svc.domains.RetrieveByID(ctx, id)
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
if err := svc.checkSuperAdmin(ctx, res.User); err != nil {
|
||||
if err = svc.Authorize(ctx, policies.Policy{
|
||||
Subject: EncodeDomainUserID(id, res.User),
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
Permission: policies.MembershipPermission,
|
||||
}); err != nil {
|
||||
return Domain{ID: domain.ID, Name: domain.Name, Alias: domain.Alias}, nil
|
||||
}
|
||||
}
|
||||
return domain, nil
|
||||
}
|
||||
|
||||
func (svc service) RetrieveDomainPermissions(ctx context.Context, token, id string) (policies.Permissions, error) {
|
||||
res, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
subject := res.User
|
||||
if err := svc.checkSuperAdmin(ctx, res.User); err != nil {
|
||||
domainUserSubject := EncodeDomainUserID(id, res.User)
|
||||
if err := svc.Authorize(ctx, policies.Policy{
|
||||
Subject: domainUserSubject,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
Permission: policies.MembershipPermission,
|
||||
}); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
subject = domainUserSubject
|
||||
}
|
||||
|
||||
lp, err := svc.policysvc.ListPermissions(ctx, policies.Policy{
|
||||
SubjectType: policies.UserType,
|
||||
Subject: subject,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
}, []string{policies.AdminPermission, policies.EditPermission, policies.ViewPermission, policies.MembershipPermission, policies.CreatePermission})
|
||||
if err != nil {
|
||||
return []string{}, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
return lp, nil
|
||||
}
|
||||
|
||||
func (svc service) UpdateDomain(ctx context.Context, token, id string, d DomainReq) (Domain, error) {
|
||||
key, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return Domain{}, err
|
||||
}
|
||||
if err := svc.checkSuperAdmin(ctx, key.User); err != nil {
|
||||
if err := svc.Authorize(ctx, policies.Policy{
|
||||
Subject: EncodeDomainUserID(id, key.User),
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
Permission: policies.EditPermission,
|
||||
}); err != nil {
|
||||
return Domain{}, err
|
||||
}
|
||||
}
|
||||
|
||||
dom, err := svc.domains.Update(ctx, id, key.User, d)
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
|
||||
}
|
||||
return dom, nil
|
||||
}
|
||||
|
||||
func (svc service) ChangeDomainStatus(ctx context.Context, token, id string, d DomainReq) (Domain, error) {
|
||||
key, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
if err := svc.checkSuperAdmin(ctx, key.User); err != nil {
|
||||
if err := svc.Authorize(ctx, policies.Policy{
|
||||
Subject: EncodeDomainUserID(id, key.User),
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
Permission: policies.AdminPermission,
|
||||
}); err != nil {
|
||||
return Domain{}, err
|
||||
}
|
||||
}
|
||||
|
||||
dom, err := svc.domains.Update(ctx, id, key.User, d)
|
||||
if err != nil {
|
||||
return Domain{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
|
||||
}
|
||||
return dom, nil
|
||||
}
|
||||
|
||||
func (svc service) ListDomains(ctx context.Context, token string, p Page) (DomainsPage, error) {
|
||||
key, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return DomainsPage{}, errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
p.SubjectID = key.User
|
||||
if err := svc.checkSuperAdmin(ctx, key.User); err == nil {
|
||||
p.SubjectID = ""
|
||||
}
|
||||
dp, err := svc.domains.ListDomains(ctx, p)
|
||||
if err != nil {
|
||||
return DomainsPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
if p.SubjectID == "" {
|
||||
for i := range dp.Domains {
|
||||
dp.Domains[i].Permission = policies.AdministratorRelation
|
||||
}
|
||||
}
|
||||
return dp, nil
|
||||
}
|
||||
|
||||
func (svc service) AssignUsers(ctx context.Context, token, id string, userIds []string, relation string) error {
|
||||
res, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
|
||||
if err := svc.checkSuperAdmin(ctx, res.User); err != nil {
|
||||
domainUserID := EncodeDomainUserID(id, res.User)
|
||||
if err := svc.Authorize(ctx, policies.Policy{
|
||||
Subject: domainUserID,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
Permission: policies.SharePermission,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := svc.Authorize(ctx, policies.Policy{
|
||||
Subject: domainUserID,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
Permission: SwitchToPermission(relation),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, userID := range userIds {
|
||||
if err := svc.Authorize(ctx, policies.Policy{
|
||||
Subject: userID,
|
||||
SubjectType: policies.UserType,
|
||||
Permission: policies.MembershipPermission,
|
||||
Object: policies.MagistralaObject,
|
||||
ObjectType: policies.PlatformType,
|
||||
}); err != nil {
|
||||
return errors.Wrap(svcerr.ErrMalformedEntity, fmt.Errorf("invalid user id : %s ", userID))
|
||||
}
|
||||
}
|
||||
|
||||
return svc.addDomainPolicies(ctx, id, relation, userIds...)
|
||||
}
|
||||
|
||||
func (svc service) UnassignUser(ctx context.Context, token, id, userID string) error {
|
||||
res, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
|
||||
if err := svc.checkSuperAdmin(ctx, res.User); err != nil {
|
||||
domainUserID := EncodeDomainUserID(id, res.User)
|
||||
pr := policies.Policy{
|
||||
Subject: domainUserID,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Object: id,
|
||||
ObjectType: policies.DomainType,
|
||||
Permission: policies.SharePermission,
|
||||
}
|
||||
if err := svc.Authorize(ctx, pr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pr.Permission = policies.AdminPermission
|
||||
if err := svc.Authorize(ctx, pr); err != nil {
|
||||
pr.SubjectKind = policies.UsersKind
|
||||
// User is not admin.
|
||||
pr.Subject = userID
|
||||
if err := svc.Authorize(ctx, pr); err == nil {
|
||||
// Non admin attempts to remove admin.
|
||||
return errors.Wrap(svcerr.ErrAuthorization, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := svc.policysvc.DeletePolicyFilter(ctx, policies.Policy{
|
||||
Subject: EncodeDomainUserID(id, userID),
|
||||
SubjectType: policies.UserType,
|
||||
}); err != nil {
|
||||
return errors.Wrap(errRemovePolicies, err)
|
||||
}
|
||||
|
||||
pc := Policy{
|
||||
SubjectType: policies.UserType,
|
||||
SubjectID: userID,
|
||||
ObjectType: policies.DomainType,
|
||||
ObjectID: id,
|
||||
}
|
||||
|
||||
if err := svc.domains.DeletePolicies(ctx, pc); err != nil {
|
||||
return errors.Wrap(errRemovePolicies, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IMPROVEMENT NOTE: Take decision: Only Patform admin or both Patform and domain admins can see others users domain.
|
||||
func (svc service) ListUserDomains(ctx context.Context, token, userID string, p Page) (DomainsPage, error) {
|
||||
res, err := svc.Identify(ctx, token)
|
||||
if err != nil {
|
||||
return DomainsPage{}, errors.Wrap(svcerr.ErrAuthentication, err)
|
||||
}
|
||||
if err := svc.checkSuperAdmin(ctx, res.User); err != nil {
|
||||
return DomainsPage{}, errors.Wrap(svcerr.ErrAuthorization, err)
|
||||
}
|
||||
if userID != "" && res.User != userID {
|
||||
p.SubjectID = userID
|
||||
} else {
|
||||
p.SubjectID = res.User
|
||||
}
|
||||
dp, err := svc.domains.ListDomains(ctx, p)
|
||||
if err != nil {
|
||||
return DomainsPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
return dp, nil
|
||||
}
|
||||
|
||||
func (svc service) addDomainPolicies(ctx context.Context, domainID, relation string, userIDs ...string) (err error) {
|
||||
var prs []policies.Policy
|
||||
var pcs []Policy
|
||||
|
||||
for _, userID := range userIDs {
|
||||
prs = append(prs, policies.Policy{
|
||||
Subject: EncodeDomainUserID(domainID, userID),
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Relation: relation,
|
||||
Object: domainID,
|
||||
ObjectType: policies.DomainType,
|
||||
})
|
||||
pcs = append(pcs, Policy{
|
||||
SubjectType: policies.UserType,
|
||||
SubjectID: userID,
|
||||
Relation: relation,
|
||||
ObjectType: policies.DomainType,
|
||||
ObjectID: domainID,
|
||||
})
|
||||
}
|
||||
if err := svc.policysvc.AddPolicies(ctx, prs); err != nil {
|
||||
return errors.Wrap(errAddPolicies, err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if errDel := svc.policysvc.DeletePolicies(ctx, prs); errDel != nil {
|
||||
err = errors.Wrap(err, errors.Wrap(errRollbackPolicy, errDel))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if err = svc.domains.SavePolicies(ctx, pcs...); err != nil {
|
||||
return errors.Wrap(errAddPolicies, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc service) createDomainPolicy(ctx context.Context, userID, domainID, relation string) (err error) {
|
||||
prs := []policies.Policy{
|
||||
{
|
||||
Subject: EncodeDomainUserID(domainID, userID),
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Relation: relation,
|
||||
Object: domainID,
|
||||
ObjectType: policies.DomainType,
|
||||
},
|
||||
{
|
||||
Subject: policies.MagistralaObject,
|
||||
SubjectType: policies.PlatformType,
|
||||
Relation: policies.PlatformRelation,
|
||||
Object: domainID,
|
||||
ObjectType: policies.DomainType,
|
||||
},
|
||||
}
|
||||
if err := svc.policysvc.AddPolicies(ctx, prs); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if errDel := svc.policysvc.DeletePolicies(ctx, prs); errDel != nil {
|
||||
err = errors.Wrap(err, errors.Wrap(errRollbackPolicy, errDel))
|
||||
}
|
||||
}
|
||||
}()
|
||||
err = svc.domains.SavePolicies(ctx, Policy{
|
||||
SubjectType: policies.UserType,
|
||||
SubjectID: userID,
|
||||
Relation: relation,
|
||||
ObjectType: policies.DomainType,
|
||||
ObjectID: domainID,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(errCreateDomainPolicy, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (svc service) createDomainPolicyRollback(ctx context.Context, userID, domainID, relation string) error {
|
||||
var err error
|
||||
prs := []policies.Policy{
|
||||
{
|
||||
Subject: EncodeDomainUserID(domainID, userID),
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Relation: relation,
|
||||
Object: domainID,
|
||||
ObjectType: policies.DomainType,
|
||||
},
|
||||
{
|
||||
Subject: policies.MagistralaObject,
|
||||
SubjectType: policies.PlatformType,
|
||||
Relation: policies.PlatformRelation,
|
||||
Object: domainID,
|
||||
ObjectType: policies.DomainType,
|
||||
},
|
||||
}
|
||||
if errPolicy := svc.policysvc.DeletePolicies(ctx, prs); errPolicy != nil {
|
||||
err = errors.Wrap(errRemovePolicyEngine, errPolicy)
|
||||
}
|
||||
errPolicyCopy := svc.domains.DeletePolicies(ctx, Policy{
|
||||
SubjectType: policies.UserType,
|
||||
SubjectID: userID,
|
||||
Relation: relation,
|
||||
ObjectType: policies.DomainType,
|
||||
ObjectID: domainID,
|
||||
})
|
||||
if errPolicyCopy != nil {
|
||||
err = errors.Wrap(err, errors.Wrap(errRemoveLocalPolicy, errPolicyCopy))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func EncodeDomainUserID(domainID, userID string) string {
|
||||
if domainID == "" || userID == "" {
|
||||
return ""
|
||||
@@ -874,51 +434,3 @@ func DecodeDomainUserID(domainUserID string) (string, string) {
|
||||
return "", ""
|
||||
}
|
||||
}
|
||||
|
||||
func (svc service) DeleteUserFromDomains(ctx context.Context, id string) (err error) {
|
||||
domainsPage, err := svc.domains.ListDomains(ctx, Page{SubjectID: id, Limit: defLimit})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if domainsPage.Total > defLimit {
|
||||
for i := defLimit; i < int(domainsPage.Total); i += defLimit {
|
||||
page := Page{SubjectID: id, Offset: uint64(i), Limit: defLimit}
|
||||
dp, err := svc.domains.ListDomains(ctx, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domainsPage.Domains = append(domainsPage.Domains, dp.Domains...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, domain := range domainsPage.Domains {
|
||||
req := policies.Policy{
|
||||
Subject: EncodeDomainUserID(domain.ID, id),
|
||||
SubjectType: policies.UserType,
|
||||
}
|
||||
if err := svc.policysvc.DeletePolicyFilter(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := svc.domains.DeleteUserPolicies(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc service) checkSuperAdmin(ctx context.Context, userID string) error {
|
||||
if err := svc.evaluator.CheckPolicy(ctx, policies.Policy{
|
||||
Subject: userID,
|
||||
SubjectType: policies.UserType,
|
||||
Permission: policies.AdminPermission,
|
||||
Object: policies.MagistralaObject,
|
||||
ObjectType: policies.PlatformType,
|
||||
}); err != nil {
|
||||
return svcerr.ErrAuthorization
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+342
-1798
File diff suppressed because it is too large
Load Diff
@@ -74,84 +74,3 @@ func (tm *tracingMiddleware) Authorize(ctx context.Context, pr policies.Policy)
|
||||
|
||||
return tm.svc.Authorize(ctx, pr)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) CreateDomain(ctx context.Context, token string, d auth.Domain) (auth.Domain, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "create_domain", trace.WithAttributes(
|
||||
attribute.String("name", d.Name),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.CreateDomain(ctx, token, d)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) RetrieveDomain(ctx context.Context, token, id string) (auth.Domain, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "view_domain", trace.WithAttributes(
|
||||
attribute.String("id", id),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.RetrieveDomain(ctx, token, id)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) RetrieveDomainPermissions(ctx context.Context, token, id string) (policies.Permissions, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "view_domain_permissions", trace.WithAttributes(
|
||||
attribute.String("id", id),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.RetrieveDomainPermissions(ctx, token, id)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) UpdateDomain(ctx context.Context, token, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "update_domain", trace.WithAttributes(
|
||||
attribute.String("id", id),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.UpdateDomain(ctx, token, id, d)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) ChangeDomainStatus(ctx context.Context, token, id string, d auth.DomainReq) (auth.Domain, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "change_domain_status", trace.WithAttributes(
|
||||
attribute.String("id", id),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.ChangeDomainStatus(ctx, token, id, d)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) ListDomains(ctx context.Context, token string, p auth.Page) (auth.DomainsPage, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "list_domains")
|
||||
defer span.End()
|
||||
return tm.svc.ListDomains(ctx, token, p)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) AssignUsers(ctx context.Context, token, id string, userIds []string, relation string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "assign_users", trace.WithAttributes(
|
||||
attribute.String("id", id),
|
||||
attribute.StringSlice("user_ids", userIds),
|
||||
attribute.String("relation", relation),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.AssignUsers(ctx, token, id, userIds, relation)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) UnassignUser(ctx context.Context, token, id, userID string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "unassign_user", trace.WithAttributes(
|
||||
attribute.String("id", id),
|
||||
attribute.String("user_id", userID),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.UnassignUser(ctx, token, id, userID)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) ListUserDomains(ctx context.Context, token, userID string, p auth.Page) (auth.DomainsPage, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "list_user_domains", trace.WithAttributes(
|
||||
attribute.String("user_id", userID),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.ListUserDomains(ctx, token, userID, p)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) DeleteUserFromDomains(ctx context.Context, id string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "delete_user_from_domains", trace.WithAttributes(
|
||||
attribute.String("id", id),
|
||||
))
|
||||
defer span.End()
|
||||
return tm.svc.DeleteUserFromDomains(ctx, id)
|
||||
}
|
||||
|
||||
-484
@@ -1,484 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.4.0
|
||||
// - protoc v5.27.1
|
||||
// source: auth.proto
|
||||
|
||||
package magistrala
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.62.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion8
|
||||
|
||||
const (
|
||||
ThingsService_Authorize_FullMethodName = "/magistrala.ThingsService/Authorize"
|
||||
)
|
||||
|
||||
// ThingsServiceClient is the client API for ThingsService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// ThingsService is a service that provides things authorization functionalities
|
||||
// for magistrala services.
|
||||
type ThingsServiceClient interface {
|
||||
// Authorize checks if the thing is authorized to perform
|
||||
// the action on the channel.
|
||||
Authorize(ctx context.Context, in *ThingsAuthzReq, opts ...grpc.CallOption) (*ThingsAuthzRes, error)
|
||||
}
|
||||
|
||||
type thingsServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewThingsServiceClient(cc grpc.ClientConnInterface) ThingsServiceClient {
|
||||
return &thingsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *thingsServiceClient) Authorize(ctx context.Context, in *ThingsAuthzReq, opts ...grpc.CallOption) (*ThingsAuthzRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ThingsAuthzRes)
|
||||
err := c.cc.Invoke(ctx, ThingsService_Authorize_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ThingsServiceServer is the server API for ThingsService service.
|
||||
// All implementations must embed UnimplementedThingsServiceServer
|
||||
// for forward compatibility
|
||||
//
|
||||
// ThingsService is a service that provides things authorization functionalities
|
||||
// for magistrala services.
|
||||
type ThingsServiceServer interface {
|
||||
// Authorize checks if the thing is authorized to perform
|
||||
// the action on the channel.
|
||||
Authorize(context.Context, *ThingsAuthzReq) (*ThingsAuthzRes, error)
|
||||
mustEmbedUnimplementedThingsServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedThingsServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedThingsServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedThingsServiceServer) Authorize(context.Context, *ThingsAuthzReq) (*ThingsAuthzRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Authorize not implemented")
|
||||
}
|
||||
func (UnimplementedThingsServiceServer) mustEmbedUnimplementedThingsServiceServer() {}
|
||||
|
||||
// UnsafeThingsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ThingsServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeThingsServiceServer interface {
|
||||
mustEmbedUnimplementedThingsServiceServer()
|
||||
}
|
||||
|
||||
func RegisterThingsServiceServer(s grpc.ServiceRegistrar, srv ThingsServiceServer) {
|
||||
s.RegisterService(&ThingsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ThingsService_Authorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ThingsAuthzReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ThingsServiceServer).Authorize(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ThingsService_Authorize_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ThingsServiceServer).Authorize(ctx, req.(*ThingsAuthzReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// ThingsService_ServiceDesc is the grpc.ServiceDesc for ThingsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var ThingsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "magistrala.ThingsService",
|
||||
HandlerType: (*ThingsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Authorize",
|
||||
Handler: _ThingsService_Authorize_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "auth.proto",
|
||||
}
|
||||
|
||||
const (
|
||||
TokenService_Issue_FullMethodName = "/magistrala.TokenService/Issue"
|
||||
TokenService_Refresh_FullMethodName = "/magistrala.TokenService/Refresh"
|
||||
)
|
||||
|
||||
// TokenServiceClient is the client API for TokenService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type TokenServiceClient interface {
|
||||
Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error)
|
||||
Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error)
|
||||
}
|
||||
|
||||
type tokenServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewTokenServiceClient(cc grpc.ClientConnInterface) TokenServiceClient {
|
||||
return &tokenServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *tokenServiceClient) Issue(ctx context.Context, in *IssueReq, opts ...grpc.CallOption) (*Token, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Token)
|
||||
err := c.cc.Invoke(ctx, TokenService_Issue_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tokenServiceClient) Refresh(ctx context.Context, in *RefreshReq, opts ...grpc.CallOption) (*Token, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Token)
|
||||
err := c.cc.Invoke(ctx, TokenService_Refresh_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// TokenServiceServer is the server API for TokenService service.
|
||||
// All implementations must embed UnimplementedTokenServiceServer
|
||||
// for forward compatibility
|
||||
type TokenServiceServer interface {
|
||||
Issue(context.Context, *IssueReq) (*Token, error)
|
||||
Refresh(context.Context, *RefreshReq) (*Token, error)
|
||||
mustEmbedUnimplementedTokenServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedTokenServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedTokenServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedTokenServiceServer) Issue(context.Context, *IssueReq) (*Token, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Issue not implemented")
|
||||
}
|
||||
func (UnimplementedTokenServiceServer) Refresh(context.Context, *RefreshReq) (*Token, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Refresh not implemented")
|
||||
}
|
||||
func (UnimplementedTokenServiceServer) mustEmbedUnimplementedTokenServiceServer() {}
|
||||
|
||||
// UnsafeTokenServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to TokenServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeTokenServiceServer interface {
|
||||
mustEmbedUnimplementedTokenServiceServer()
|
||||
}
|
||||
|
||||
func RegisterTokenServiceServer(s grpc.ServiceRegistrar, srv TokenServiceServer) {
|
||||
s.RegisterService(&TokenService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _TokenService_Issue_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(IssueReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TokenServiceServer).Issue(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: TokenService_Issue_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TokenServiceServer).Issue(ctx, req.(*IssueReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _TokenService_Refresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RefreshReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TokenServiceServer).Refresh(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: TokenService_Refresh_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TokenServiceServer).Refresh(ctx, req.(*RefreshReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// TokenService_ServiceDesc is the grpc.ServiceDesc for TokenService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var TokenService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "magistrala.TokenService",
|
||||
HandlerType: (*TokenServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Issue",
|
||||
Handler: _TokenService_Issue_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Refresh",
|
||||
Handler: _TokenService_Refresh_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "auth.proto",
|
||||
}
|
||||
|
||||
const (
|
||||
AuthService_Authorize_FullMethodName = "/magistrala.AuthService/Authorize"
|
||||
AuthService_Authenticate_FullMethodName = "/magistrala.AuthService/Authenticate"
|
||||
)
|
||||
|
||||
// AuthServiceClient is the client API for AuthService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// AuthService is a service that provides authentication and authorization
|
||||
// functionalities for magistrala services.
|
||||
type AuthServiceClient interface {
|
||||
Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error)
|
||||
Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
|
||||
}
|
||||
|
||||
type authServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
|
||||
return &authServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *authServiceClient) Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(AuthZRes)
|
||||
err := c.cc.Invoke(ctx, AuthService_Authorize_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authServiceClient) Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(AuthNRes)
|
||||
err := c.cc.Invoke(ctx, AuthService_Authenticate_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AuthServiceServer is the server API for AuthService service.
|
||||
// All implementations must embed UnimplementedAuthServiceServer
|
||||
// for forward compatibility
|
||||
//
|
||||
// AuthService is a service that provides authentication and authorization
|
||||
// functionalities for magistrala services.
|
||||
type AuthServiceServer interface {
|
||||
Authorize(context.Context, *AuthZReq) (*AuthZRes, error)
|
||||
Authenticate(context.Context, *AuthNReq) (*AuthNRes, error)
|
||||
mustEmbedUnimplementedAuthServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedAuthServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedAuthServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedAuthServiceServer) Authorize(context.Context, *AuthZReq) (*AuthZRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Authorize not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) Authenticate(context.Context, *AuthNReq) (*AuthNRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Authenticate not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
|
||||
|
||||
// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to AuthServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeAuthServiceServer interface {
|
||||
mustEmbedUnimplementedAuthServiceServer()
|
||||
}
|
||||
|
||||
func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
|
||||
s.RegisterService(&AuthService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _AuthService_Authorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AuthZReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthServiceServer).Authorize(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthService_Authorize_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthServiceServer).Authorize(ctx, req.(*AuthZReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AuthService_Authenticate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AuthNReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthServiceServer).Authenticate(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthService_Authenticate_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthServiceServer).Authenticate(ctx, req.(*AuthNReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var AuthService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "magistrala.AuthService",
|
||||
HandlerType: (*AuthServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Authorize",
|
||||
Handler: _AuthService_Authorize_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Authenticate",
|
||||
Handler: _AuthService_Authenticate_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "auth.proto",
|
||||
}
|
||||
|
||||
const (
|
||||
DomainsService_DeleteUserFromDomains_FullMethodName = "/magistrala.DomainsService/DeleteUserFromDomains"
|
||||
)
|
||||
|
||||
// DomainsServiceClient is the client API for DomainsService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// DomainsService is a service that provides access to domains
|
||||
// functionalities for magistrala services.
|
||||
type DomainsServiceClient interface {
|
||||
DeleteUserFromDomains(ctx context.Context, in *DeleteUserReq, opts ...grpc.CallOption) (*DeleteUserRes, error)
|
||||
}
|
||||
|
||||
type domainsServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewDomainsServiceClient(cc grpc.ClientConnInterface) DomainsServiceClient {
|
||||
return &domainsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *domainsServiceClient) DeleteUserFromDomains(ctx context.Context, in *DeleteUserReq, opts ...grpc.CallOption) (*DeleteUserRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeleteUserRes)
|
||||
err := c.cc.Invoke(ctx, DomainsService_DeleteUserFromDomains_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DomainsServiceServer is the server API for DomainsService service.
|
||||
// All implementations must embed UnimplementedDomainsServiceServer
|
||||
// for forward compatibility
|
||||
//
|
||||
// DomainsService is a service that provides access to domains
|
||||
// functionalities for magistrala services.
|
||||
type DomainsServiceServer interface {
|
||||
DeleteUserFromDomains(context.Context, *DeleteUserReq) (*DeleteUserRes, error)
|
||||
mustEmbedUnimplementedDomainsServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedDomainsServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedDomainsServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedDomainsServiceServer) DeleteUserFromDomains(context.Context, *DeleteUserReq) (*DeleteUserRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteUserFromDomains not implemented")
|
||||
}
|
||||
func (UnimplementedDomainsServiceServer) mustEmbedUnimplementedDomainsServiceServer() {}
|
||||
|
||||
// UnsafeDomainsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to DomainsServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeDomainsServiceServer interface {
|
||||
mustEmbedUnimplementedDomainsServiceServer()
|
||||
}
|
||||
|
||||
func RegisterDomainsServiceServer(s grpc.ServiceRegistrar, srv DomainsServiceServer) {
|
||||
s.RegisterService(&DomainsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _DomainsService_DeleteUserFromDomains_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteUserReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DomainsServiceServer).DeleteUserFromDomains(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: DomainsService_DeleteUserFromDomains_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DomainsServiceServer).DeleteUserFromDomains(ctx, req.(*DeleteUserReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// DomainsService_ServiceDesc is the grpc.ServiceDesc for DomainsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var DomainsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "magistrala.DomainsService",
|
||||
HandlerType: (*DomainsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "DeleteUserFromDomains",
|
||||
Handler: _DomainsService_DeleteUserFromDomains_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "auth.proto",
|
||||
}
|
||||
+46
-46
@@ -2,68 +2,68 @@
|
||||
|
||||
New devices need to be configured properly and connected to the Magistrala. Bootstrap service is used in order to accomplish that. This service provides the following features:
|
||||
|
||||
1. Creating new Magistrala Things
|
||||
2. Providing basic configuration for the newly created Things
|
||||
3. Enabling/disabling Things
|
||||
1. Creating new Magistrala Clients
|
||||
2. Providing basic configuration for the newly created Clients
|
||||
3. Enabling/disabling Clients
|
||||
|
||||
Pre-provisioning a new Thing is as simple as sending Configuration data to the Bootstrap service. Once the Thing is online, it sends a request for initial config to Bootstrap service. Bootstrap service provides an API for enabling and disabling Things. Only enabled Things can exchange messages over Magistrala. Bootstrapping does not implicitly enable Things, it has to be done manually.
|
||||
Pre-provisioning a new Client is as simple as sending Configuration data to the Bootstrap service. Once the Client is online, it sends a request for initial config to Bootstrap service. Bootstrap service provides an API for enabling and disabling Clients. Only enabled Clients can exchange messages over Magistrala. Bootstrapping does not implicitly enable Clients, it has to be done manually.
|
||||
|
||||
In order to bootstrap successfully, the Thing needs to send bootstrapping request to the specific URL, as well as a secret key. This key and URL are pre-provisioned during the manufacturing process. If the Thing is provisioned on the Bootstrap service side, the corresponding configuration will be sent as a response. Otherwise, the Thing will be saved so that it can be provisioned later.
|
||||
In order to bootstrap successfully, the Client needs to send bootstrapping request to the specific URL, as well as a secret key. This key and URL are pre-provisioned during the manufacturing process. If the Client is provisioned on the Bootstrap service side, the corresponding configuration will be sent as a response. Otherwise, the Client will be saved so that it can be provisioned later.
|
||||
|
||||
## Thing Configuration Entity
|
||||
## Client Configuration Entity
|
||||
|
||||
Thing Configuration consists of two logical parts: the custom configuration that can be interpreted by the Thing itself and Magistrala-related configuration. Magistrala config contains:
|
||||
Client Configuration consists of two logical parts: the custom configuration that can be interpreted by the Client itself and Magistrala-related configuration. Magistrala config contains:
|
||||
|
||||
1. corresponding Magistrala Thing ID
|
||||
2. corresponding Magistrala Thing key
|
||||
3. list of the Magistrala channels the Thing is connected to
|
||||
1. corresponding Magistrala Client ID
|
||||
2. corresponding Magistrala Client key
|
||||
3. list of the Magistrala channels the Client is connected to
|
||||
|
||||
> Note: list of channels contains IDs of the Magistrala channels. These channels are _pre-provisioned_ on the Magistrala side and, unlike corresponding Magistrala Thing, Bootstrap service is not able to create Magistrala Channels.
|
||||
> Note: list of channels contains IDs of the Magistrala channels. These channels are _pre-provisioned_ on the Magistrala side and, unlike corresponding Magistrala Client, Bootstrap service is not able to create Magistrala Channels.
|
||||
|
||||
Enabling and disabling Thing (adding Thing to/from whitelist) is as simple as connecting corresponding Magistrala Thing to the given list of Channels. Configuration keeps _state_ of the Thing:
|
||||
Enabling and disabling Client (adding Client to/from whitelist) is as simple as connecting corresponding Magistrala Client to the given list of Channels. Configuration keeps _state_ of the Client:
|
||||
|
||||
| State | What it means |
|
||||
| -------- | --------------------------------------------- |
|
||||
| Inactive | Thing is created, but isn't enabled |
|
||||
| Active | Thing is able to communicate using Magistrala |
|
||||
| Inactive | Client is created, but isn't enabled |
|
||||
| Active | Client is able to communicate using Magistrala |
|
||||
|
||||
Switching between states `Active` and `Inactive` enables and disables Thing, respectively.
|
||||
Switching between states `Active` and `Inactive` enables and disables Client, respectively.
|
||||
|
||||
Thing configuration also contains the so-called `external ID` and `external key`. An external ID is a unique identifier of corresponding Thing. For example, a device MAC address is a good choice for external ID. External key is a secret key that is used for authentication during the bootstrapping procedure.
|
||||
Client configuration also contains the so-called `external ID` and `external key`. An external ID is a unique identifier of corresponding Client. For example, a device MAC address is a good choice for external ID. External key is a secret key that is used for authentication during the bootstrapping procedure.
|
||||
|
||||
## Configuration
|
||||
|
||||
The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.
|
||||
|
||||
| Variable | Description | Default |
|
||||
| ----------------------------- | -------------------------------------------------------------------------------- | -------------------------------- |
|
||||
| MG_BOOTSTRAP_LOG_LEVEL | Log level for Bootstrap (debug, info, warn, error) | info |
|
||||
| MG_BOOTSTRAP_DB_HOST | Database host address | localhost |
|
||||
| MG_BOOTSTRAP_DB_PORT | Database host port | 5432 |
|
||||
| MG_BOOTSTRAP_DB_USER | Database user | magistrala |
|
||||
| MG_BOOTSTRAP_DB_PASS | Database password | magistrala |
|
||||
| MG_BOOTSTRAP_DB_NAME | Name of the database used by the service | bootstrap |
|
||||
| MG_BOOTSTRAP_DB_SSL_MODE | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
|
||||
| MG_BOOTSTRAP_DB_SSL_CERT | Path to the PEM encoded certificate file | "" |
|
||||
| MG_BOOTSTRAP_DB_SSL_KEY | Path to the PEM encoded key file | "" |
|
||||
| MG_BOOTSTRAP_DB_SSL_ROOT_CERT | Path to the PEM encoded root certificate file | "" |
|
||||
| MG_BOOTSTRAP_ENCRYPT_KEY | Secret key for secure bootstrapping encryption | 12345678910111213141516171819202 |
|
||||
| MG_BOOTSTRAP_HTTP_HOST | Bootstrap service HTTP host | "" |
|
||||
| MG_BOOTSTRAP_HTTP_PORT | Bootstrap service HTTP port | 9013 |
|
||||
| MG_BOOTSTRAP_HTTP_SERVER_CERT | Path to server certificate in pem format | "" |
|
||||
| MG_BOOTSTRAP_HTTP_SERVER_KEY | Path to server key in pem format | "" |
|
||||
| MG_BOOTSTRAP_EVENT_CONSUMER | Bootstrap service event source consumer name | bootstrap |
|
||||
| MG_ES_URL | Event store URL | <nats://localhost:4222> |
|
||||
| MG_AUTH_GRPC_URL | Auth service Auth gRPC URL | <localhost:8181> |
|
||||
| MG_AUTH_GRPC_TIMEOUT | Auth service Auth gRPC request timeout in seconds | 1s |
|
||||
| MG_AUTH_GRPC_CLIENT_CERT | Path to the PEM encoded auth service Auth gRPC client certificate file | "" |
|
||||
| MG_AUTH_GRPC_CLIENT_KEY | Path to the PEM encoded auth service Auth gRPC client key file | "" |
|
||||
| MG_AUTH_GRPC_SERVER_CERTS | Path to the PEM encoded auth server Auth gRPC server trusted CA certificate file | "" |
|
||||
| MG_THINGS_URL | Base url for Magistrala Things | <http://localhost:9000> |
|
||||
| MG_JAEGER_URL | Jaeger server URL | <http://localhost:4318/v1/traces> |
|
||||
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
|
||||
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server | true |
|
||||
| MG_BOOTSTRAP_INSTANCE_ID | Bootstrap service instance ID | "" |
|
||||
| Variable | Description | Default |
|
||||
| ----------------------------- | -------------------------------------------------------------------------------- | --------------------------------- |
|
||||
| MG_BOOTSTRAP_LOG_LEVEL | Log level for Bootstrap (debug, info, warn, error) | info |
|
||||
| MG_BOOTSTRAP_DB_HOST | Database host address | localhost |
|
||||
| MG_BOOTSTRAP_DB_PORT | Database host port | 5432 |
|
||||
| MG_BOOTSTRAP_DB_USER | Database user | magistrala |
|
||||
| MG_BOOTSTRAP_DB_PASS | Database password | magistrala |
|
||||
| MG_BOOTSTRAP_DB_NAME | Name of the database used by the service | bootstrap |
|
||||
| MG_BOOTSTRAP_DB_SSL_MODE | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
|
||||
| MG_BOOTSTRAP_DB_SSL_CERT | Path to the PEM encoded certificate file | "" |
|
||||
| MG_BOOTSTRAP_DB_SSL_KEY | Path to the PEM encoded key file | "" |
|
||||
| MG_BOOTSTRAP_DB_SSL_ROOT_CERT | Path to the PEM encoded root certificate file | "" |
|
||||
| MG_BOOTSTRAP_ENCRYPT_KEY | Secret key for secure bootstrapping encryption | 12345678910111213141516171819202 |
|
||||
| MG_BOOTSTRAP_HTTP_HOST | Bootstrap service HTTP host | "" |
|
||||
| MG_BOOTSTRAP_HTTP_PORT | Bootstrap service HTTP port | 9013 |
|
||||
| MG_BOOTSTRAP_HTTP_SERVER_CERT | Path to server certificate in pem format | "" |
|
||||
| MG_BOOTSTRAP_HTTP_SERVER_KEY | Path to server key in pem format | "" |
|
||||
| MG_BOOTSTRAP_EVENT_CONSUMER | Bootstrap service event source consumer name | bootstrap |
|
||||
| MG_ES_URL | Event store URL | <nats://localhost:4222> |
|
||||
| MG_AUTH_GRPC_URL | Auth service Auth gRPC URL | <localhost:8181> |
|
||||
| MG_AUTH_GRPC_TIMEOUT | Auth service Auth gRPC request timeout in seconds | 1s |
|
||||
| MG_AUTH_GRPC_CLIENT_CERT | Path to the PEM encoded auth service Auth gRPC client certificate file | "" |
|
||||
| MG_AUTH_GRPC_CLIENT_KEY | Path to the PEM encoded auth service Auth gRPC client key file | "" |
|
||||
| MG_AUTH_GRPC_SERVER_CERTS | Path to the PEM encoded auth server Auth gRPC server trusted CA certificate file | "" |
|
||||
| MG_CLIENTS_URL | Base URL for Magistrala Clients | <http://localhost:9000> |
|
||||
| MG_JAEGER_URL | Jaeger server URL | <http://localhost:4318/v1/traces> |
|
||||
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
|
||||
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server | true |
|
||||
| MG_BOOTSTRAP_INSTANCE_ID | Bootstrap service instance ID | "" |
|
||||
|
||||
## Deployment
|
||||
|
||||
@@ -105,7 +105,7 @@ MG_AUTH_GRPC_TIMEOUT=1s \
|
||||
MG_AUTH_GRPC_CLIENT_CERT="" \
|
||||
MG_AUTH_GRPC_CLIENT_KEY="" \
|
||||
MG_AUTH_GRPC_SERVER_CERTS="" \
|
||||
MG_THINGS_URL=http://localhost:9000 \
|
||||
MG_CLIENTS_URL=http://localhost:9000 \
|
||||
MG_JAEGER_URL=http://localhost:14268/api/traces \
|
||||
MG_JAEGER_TRACE_RATIO=1.0 \
|
||||
MG_SEND_TELEMETRY=true \
|
||||
|
||||
+24
-24
@@ -33,7 +33,7 @@ func addEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
config := bootstrap.Config{
|
||||
ThingID: req.ThingID,
|
||||
ClientID: req.ClientID,
|
||||
ExternalID: req.ExternalID,
|
||||
ExternalKey: req.ExternalKey,
|
||||
Channels: channels,
|
||||
@@ -50,7 +50,7 @@ func addEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
res := configRes{
|
||||
id: saved.ThingID,
|
||||
id: saved.ClientID,
|
||||
created: true,
|
||||
}
|
||||
|
||||
@@ -70,13 +70,13 @@ func updateCertEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
return nil, svcerr.ErrAuthorization
|
||||
}
|
||||
|
||||
cfg, err := svc.UpdateCert(ctx, session, req.thingID, req.ClientCert, req.ClientKey, req.CACert)
|
||||
cfg, err := svc.UpdateCert(ctx, session, req.clientID, req.ClientCert, req.ClientKey, req.CACert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := updateConfigRes{
|
||||
ThingID: cfg.ThingID,
|
||||
ClientID: cfg.ClientID,
|
||||
ClientCert: cfg.ClientCert,
|
||||
CACert: cfg.CACert,
|
||||
ClientKey: cfg.ClientKey,
|
||||
@@ -113,14 +113,14 @@ func viewEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
res := viewRes{
|
||||
ThingID: config.ThingID,
|
||||
ThingKey: config.ThingKey,
|
||||
Channels: channels,
|
||||
ExternalID: config.ExternalID,
|
||||
ExternalKey: config.ExternalKey,
|
||||
Name: config.Name,
|
||||
Content: config.Content,
|
||||
State: config.State,
|
||||
ClientID: config.ClientID,
|
||||
CLientSecret: config.ClientSecret,
|
||||
Channels: channels,
|
||||
ExternalID: config.ExternalID,
|
||||
ExternalKey: config.ExternalKey,
|
||||
Name: config.Name,
|
||||
Content: config.Content,
|
||||
State: config.State,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
@@ -140,9 +140,9 @@ func updateEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
config := bootstrap.Config{
|
||||
ThingID: req.id,
|
||||
Name: req.Name,
|
||||
Content: req.Content,
|
||||
ClientID: req.id,
|
||||
Name: req.Name,
|
||||
Content: req.Content,
|
||||
}
|
||||
|
||||
if err := svc.Update(ctx, session, config); err != nil {
|
||||
@@ -150,7 +150,7 @@ func updateEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
res := configRes{
|
||||
id: config.ThingID,
|
||||
id: config.ClientID,
|
||||
created: false,
|
||||
}
|
||||
|
||||
@@ -217,14 +217,14 @@ func listEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
view := viewRes{
|
||||
ThingID: cfg.ThingID,
|
||||
ThingKey: cfg.ThingKey,
|
||||
Channels: channels,
|
||||
ExternalID: cfg.ExternalID,
|
||||
ExternalKey: cfg.ExternalKey,
|
||||
Name: cfg.Name,
|
||||
Content: cfg.Content,
|
||||
State: cfg.State,
|
||||
ClientID: cfg.ClientID,
|
||||
CLientSecret: cfg.ClientSecret,
|
||||
Channels: channels,
|
||||
ExternalID: cfg.ExternalID,
|
||||
ExternalKey: cfg.ExternalKey,
|
||||
Name: cfg.Name,
|
||||
Content: cfg.Content,
|
||||
State: cfg.State,
|
||||
}
|
||||
res.Configs = append(res.Configs, view)
|
||||
}
|
||||
|
||||
+127
-127
@@ -49,44 +49,44 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
encKey = []byte("1234567891011121")
|
||||
metadata = map[string]interface{}{"meta": "data"}
|
||||
addExternalID = testsutil.GenerateUUID(&testing.T{})
|
||||
addExternalKey = testsutil.GenerateUUID(&testing.T{})
|
||||
addThingID = testsutil.GenerateUUID(&testing.T{})
|
||||
addThingKey = testsutil.GenerateUUID(&testing.T{})
|
||||
addReq = struct {
|
||||
ThingID string `json:"thing_id"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key"`
|
||||
Channels []string `json:"channels"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
encKey = []byte("1234567891011121")
|
||||
metadata = map[string]interface{}{"meta": "data"}
|
||||
addExternalID = testsutil.GenerateUUID(&testing.T{})
|
||||
addExternalKey = testsutil.GenerateUUID(&testing.T{})
|
||||
addClientID = testsutil.GenerateUUID(&testing.T{})
|
||||
addClientSecret = testsutil.GenerateUUID(&testing.T{})
|
||||
addReq = struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key"`
|
||||
Channels []string `json:"channels"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
}{
|
||||
ThingID: addThingID,
|
||||
ThingKey: addThingKey,
|
||||
ExternalID: addExternalID,
|
||||
ExternalKey: addExternalKey,
|
||||
Channels: []string{"1"},
|
||||
Name: "name",
|
||||
Content: "config",
|
||||
ClientID: addClientID,
|
||||
ClientSecret: addClientSecret,
|
||||
ExternalID: addExternalID,
|
||||
ExternalKey: addExternalKey,
|
||||
Channels: []string{"1"},
|
||||
Name: "name",
|
||||
Content: "config",
|
||||
}
|
||||
|
||||
updateReq = struct {
|
||||
Channels []string `json:"channels,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
State bootstrap.State `json:"state,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
Channels []string `json:"channels,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
State bootstrap.State `json:"state,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientSecret string `json:"client_secret,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
}{
|
||||
Channels: []string{"1"},
|
||||
Content: "config update",
|
||||
State: 1,
|
||||
ClientCert: "newcert",
|
||||
ClientKey: "newkey",
|
||||
CACert: "newca",
|
||||
Channels: []string{"1"},
|
||||
Content: "config update",
|
||||
State: 1,
|
||||
ClientCert: "newcert",
|
||||
ClientSecret: "newkey",
|
||||
CACert: "newca",
|
||||
}
|
||||
|
||||
missingIDRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrMissingID.Error(), Msg: apiutil.ErrValidation.Error()})
|
||||
@@ -108,10 +108,10 @@ type testRequest struct {
|
||||
|
||||
func newConfig() bootstrap.Config {
|
||||
return bootstrap.Config{
|
||||
ThingID: addThingID,
|
||||
ThingKey: addThingKey,
|
||||
ExternalID: addExternalID,
|
||||
ExternalKey: addExternalKey,
|
||||
ClientID: addClientID,
|
||||
ClientSecret: addClientSecret,
|
||||
ExternalID: addExternalID,
|
||||
ExternalKey: addExternalKey,
|
||||
Channels: []bootstrap.Channel{
|
||||
{
|
||||
ID: "1",
|
||||
@@ -136,7 +136,7 @@ func (tr testRequest) make() (*http.Response, error) {
|
||||
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
|
||||
}
|
||||
if tr.key != "" {
|
||||
req.Header.Set("Authorization", apiutil.ThingPrefix+tr.key)
|
||||
req.Header.Set("Authorization", apiutil.ClientPrefix+tr.key)
|
||||
}
|
||||
|
||||
if tr.contentType != "" {
|
||||
@@ -200,7 +200,7 @@ func TestAdd(t *testing.T) {
|
||||
data := toJSON(addReq)
|
||||
|
||||
neID := addReq
|
||||
neID.ThingID = testsutil.GenerateUUID(t)
|
||||
neID.ClientID = testsutil.GenerateUUID(t)
|
||||
neData := toJSON(neID)
|
||||
|
||||
invalidChannels := addReq
|
||||
@@ -237,7 +237,7 @@ func TestAdd(t *testing.T) {
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusCreated,
|
||||
location: "/things/configs/" + c.ThingID,
|
||||
location: "/clients/configs/" + c.ClientID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@@ -332,7 +332,7 @@ func TestAdd(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodPost,
|
||||
url: fmt.Sprintf("%s/%s/things/configs", bs.URL, tc.domainID),
|
||||
url: fmt.Sprintf("%s/%s/clients/configs", bs.URL, tc.domainID),
|
||||
contentType: tc.contentType,
|
||||
token: tc.token,
|
||||
body: strings.NewReader(tc.req),
|
||||
@@ -359,14 +359,14 @@ func TestView(t *testing.T) {
|
||||
}
|
||||
|
||||
data := config{
|
||||
ThingID: c.ThingID,
|
||||
ThingKey: c.ThingKey,
|
||||
State: c.State,
|
||||
Channels: channels,
|
||||
ExternalID: c.ExternalID,
|
||||
ExternalKey: c.ExternalKey,
|
||||
Name: c.Name,
|
||||
Content: c.Content,
|
||||
ClientID: c.ClientID,
|
||||
ClientSecret: c.ClientSecret,
|
||||
State: c.State,
|
||||
Channels: channels,
|
||||
ExternalID: c.ExternalID,
|
||||
ExternalKey: c.ExternalKey,
|
||||
Name: c.Name,
|
||||
Content: c.Content,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
@@ -382,7 +382,7 @@ func TestView(t *testing.T) {
|
||||
{
|
||||
desc: "view a config with invalid token",
|
||||
token: invalidToken,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
status: http.StatusUnauthorized,
|
||||
res: config{},
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
@@ -391,7 +391,7 @@ func TestView(t *testing.T) {
|
||||
{
|
||||
desc: "view a config",
|
||||
token: validToken,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
status: http.StatusOK,
|
||||
res: data,
|
||||
err: nil,
|
||||
@@ -407,7 +407,7 @@ func TestView(t *testing.T) {
|
||||
{
|
||||
desc: "view a config with an empty token",
|
||||
token: "",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
status: http.StatusUnauthorized,
|
||||
res: config{},
|
||||
err: apiutil.ErrBearerToken,
|
||||
@@ -415,7 +415,7 @@ func TestView(t *testing.T) {
|
||||
{
|
||||
desc: "view config without authorization",
|
||||
token: validToken,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
status: http.StatusForbidden,
|
||||
res: config{},
|
||||
err: svcerr.ErrAuthorization,
|
||||
@@ -432,7 +432,7 @@ func TestView(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/%s/things/configs/%s", bs.URL, domainID, tc.id),
|
||||
url: fmt.Sprintf("%s/%s/clients/configs/%s", bs.URL, domainID, tc.id),
|
||||
token: tc.token,
|
||||
}
|
||||
res, err := req.make()
|
||||
@@ -476,7 +476,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update with invalid token",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: invalidToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -486,7 +486,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update with an empty token",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: "",
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -495,7 +495,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update a valid config",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusOK,
|
||||
@@ -504,7 +504,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with wrong content type",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: "",
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
@@ -522,7 +522,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with invalid request format",
|
||||
req: "}",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
@@ -530,7 +530,7 @@ func TestUpdate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update a config with an empty request",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
req: "",
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
@@ -549,7 +549,7 @@ func TestUpdate(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%s/things/configs/%s", bs.URL, domainID, tc.id),
|
||||
url: fmt.Sprintf("%s/%s/clients/configs/%s", bs.URL, domainID, tc.id),
|
||||
contentType: tc.contentType,
|
||||
token: tc.token,
|
||||
body: strings.NewReader(tc.req),
|
||||
@@ -584,7 +584,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update with invalid token",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: invalidToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -594,7 +594,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update with an empty token",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: "",
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -603,7 +603,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update a valid config",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusOK,
|
||||
@@ -612,7 +612,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with wrong content type",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: "",
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
@@ -630,7 +630,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with invalid request format",
|
||||
req: "}",
|
||||
id: c.ThingKey,
|
||||
id: c.ClientSecret,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
@@ -638,7 +638,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update a config with an empty request",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
req: "",
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
@@ -657,7 +657,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodPatch,
|
||||
url: fmt.Sprintf("%s/%s/things/configs/certs/%s", bs.URL, domainID, tc.id),
|
||||
url: fmt.Sprintf("%s/%s/clients/configs/certs/%s", bs.URL, domainID, tc.id),
|
||||
contentType: tc.contentType,
|
||||
token: tc.token,
|
||||
body: strings.NewReader(tc.req),
|
||||
@@ -696,7 +696,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with invalid token",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: invalidToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -706,7 +706,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with an empty token",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: "",
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -715,7 +715,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections valid config",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusOK,
|
||||
@@ -724,7 +724,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with wrong content type",
|
||||
req: data,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: "",
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
@@ -742,7 +742,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with invalid channels",
|
||||
req: wrongData,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusNotFound,
|
||||
@@ -751,7 +751,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with invalid request format",
|
||||
req: "}",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
@@ -759,7 +759,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update a config with an empty request",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
req: "",
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
@@ -778,7 +778,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%s/things/configs/connections/%s", bs.URL, domainID, tc.id),
|
||||
url: fmt.Sprintf("%s/%s/clients/configs/connections/%s", bs.URL, domainID, tc.id),
|
||||
contentType: tc.contentType,
|
||||
token: tc.token,
|
||||
body: strings.NewReader(tc.req),
|
||||
@@ -800,13 +800,13 @@ func TestList(t *testing.T) {
|
||||
|
||||
bs, svc, auth := newBootstrapServer()
|
||||
defer bs.Close()
|
||||
path := fmt.Sprintf("%s/%s/%s", bs.URL, domainID, "things/configs")
|
||||
path := fmt.Sprintf("%s/%s/%s", bs.URL, domainID, "clients/configs")
|
||||
|
||||
c := newConfig()
|
||||
|
||||
for i := 0; i < configNum; i++ {
|
||||
c.ExternalID = strconv.Itoa(i)
|
||||
c.ThingKey = c.ExternalID
|
||||
c.ClientSecret = c.ExternalID
|
||||
c.Name = fmt.Sprintf("%s-%d", addName, i)
|
||||
c.ExternalKey = fmt.Sprintf("%s%s", addExternalKey, strconv.Itoa(i))
|
||||
|
||||
@@ -815,14 +815,14 @@ func TestList(t *testing.T) {
|
||||
channels = append(channels, channel{ID: ch.ID, Name: ch.Name, Metadata: ch.Metadata})
|
||||
}
|
||||
s := config{
|
||||
ThingID: c.ThingID,
|
||||
ThingKey: c.ThingKey,
|
||||
Channels: channels,
|
||||
ExternalID: c.ExternalID,
|
||||
ExternalKey: c.ExternalKey,
|
||||
Name: c.Name,
|
||||
Content: c.Content,
|
||||
State: c.State,
|
||||
ClientID: c.ClientID,
|
||||
ClientSecret: c.ClientSecret,
|
||||
Channels: channels,
|
||||
ExternalID: c.ExternalID,
|
||||
ExternalKey: c.ExternalKey,
|
||||
Name: c.Name,
|
||||
Content: c.Content,
|
||||
State: c.State,
|
||||
}
|
||||
list[i] = s
|
||||
}
|
||||
@@ -833,7 +833,7 @@ func TestList(t *testing.T) {
|
||||
state = bootstrap.Inactive
|
||||
}
|
||||
svcCall := svc.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
err := svc.ChangeState(context.Background(), mgauthn.Session{}, validToken, list[i].ThingID, state)
|
||||
err := svc.ChangeState(context.Background(), mgauthn.Session{}, validToken, list[i].ClientID, state)
|
||||
assert.Nil(t, err, fmt.Sprintf("Changing state expected to succeed: %s.\n", err))
|
||||
|
||||
svcCall.Unset()
|
||||
@@ -1084,7 +1084,7 @@ func TestRemove(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "remove with invalid token",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: invalidToken,
|
||||
status: http.StatusUnauthorized,
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
@@ -1092,7 +1092,7 @@ func TestRemove(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "remove with an empty token",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: "",
|
||||
status: http.StatusUnauthorized,
|
||||
err: apiutil.ErrBearerToken,
|
||||
@@ -1106,7 +1106,7 @@ func TestRemove(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "remove config",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
status: http.StatusNoContent,
|
||||
err: nil,
|
||||
@@ -1130,7 +1130,7 @@ func TestRemove(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/%s/things/configs/%s", bs.URL, domainID, tc.id),
|
||||
url: fmt.Sprintf("%s/%s/clients/configs/%s", bs.URL, domainID, tc.id),
|
||||
token: tc.token,
|
||||
}
|
||||
res, err := req.make()
|
||||
@@ -1156,21 +1156,21 @@ func TestBootstrap(t *testing.T) {
|
||||
}
|
||||
|
||||
s := struct {
|
||||
ThingID string `json:"thing_id"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []channel `json:"channels"`
|
||||
Content string `json:"content"`
|
||||
ClientCert string `json:"client_cert"`
|
||||
ClientKey string `json:"client_key"`
|
||||
CACert string `json:"ca_cert"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
Channels []channel `json:"channels"`
|
||||
Content string `json:"content"`
|
||||
ClientCert string `json:"client_cert"`
|
||||
ClientKey string `json:"client_key"`
|
||||
CACert string `json:"ca_cert"`
|
||||
}{
|
||||
ThingID: c.ThingID,
|
||||
ThingKey: c.ThingKey,
|
||||
Channels: channels,
|
||||
Content: c.Content,
|
||||
ClientCert: c.ClientCert,
|
||||
ClientKey: c.ClientKey,
|
||||
CACert: c.CACert,
|
||||
ClientID: c.ClientID,
|
||||
ClientSecret: c.ClientSecret,
|
||||
Channels: channels,
|
||||
Content: c.Content,
|
||||
ClientCert: c.ClientCert,
|
||||
ClientKey: c.ClientKey,
|
||||
CACert: c.CACert,
|
||||
}
|
||||
|
||||
data := toJSON(s)
|
||||
@@ -1185,7 +1185,7 @@ func TestBootstrap(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "bootstrap a Thing with unknown ID",
|
||||
desc: "bootstrap a Client with unknown ID",
|
||||
externalID: unknown,
|
||||
externalKey: c.ExternalKey,
|
||||
status: http.StatusNotFound,
|
||||
@@ -1194,7 +1194,7 @@ func TestBootstrap(t *testing.T) {
|
||||
err: bootstrap.ErrBootstrap,
|
||||
},
|
||||
{
|
||||
desc: "bootstrap a Thing with an empty ID",
|
||||
desc: "bootstrap a Client with an empty ID",
|
||||
externalID: "",
|
||||
externalKey: c.ExternalKey,
|
||||
status: http.StatusBadRequest,
|
||||
@@ -1203,7 +1203,7 @@ func TestBootstrap(t *testing.T) {
|
||||
err: errors.Wrap(bootstrap.ErrBootstrap, svcerr.ErrMalformedEntity),
|
||||
},
|
||||
{
|
||||
desc: "bootstrap a Thing with unknown key",
|
||||
desc: "bootstrap a Client with unknown key",
|
||||
externalID: c.ExternalID,
|
||||
externalKey: unknown,
|
||||
status: http.StatusForbidden,
|
||||
@@ -1212,7 +1212,7 @@ func TestBootstrap(t *testing.T) {
|
||||
err: errors.Wrap(bootstrap.ErrExternalKey, errors.New("")),
|
||||
},
|
||||
{
|
||||
desc: "bootstrap a Thing with an empty key",
|
||||
desc: "bootstrap a Client with an empty key",
|
||||
externalID: c.ExternalID,
|
||||
externalKey: "",
|
||||
status: http.StatusBadRequest,
|
||||
@@ -1221,7 +1221,7 @@ func TestBootstrap(t *testing.T) {
|
||||
err: errors.Wrap(bootstrap.ErrBootstrap, svcerr.ErrAuthentication),
|
||||
},
|
||||
{
|
||||
desc: "bootstrap known Thing",
|
||||
desc: "bootstrap known Client",
|
||||
externalID: c.ExternalID,
|
||||
externalKey: c.ExternalKey,
|
||||
status: http.StatusOK,
|
||||
@@ -1255,7 +1255,7 @@ func TestBootstrap(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/things/bootstrap/%s", bs.URL, tc.externalID),
|
||||
url: fmt.Sprintf("%s/clients/bootstrap/%s", bs.URL, tc.externalID),
|
||||
key: tc.externalKey,
|
||||
}
|
||||
res, err := req.make()
|
||||
@@ -1296,7 +1296,7 @@ func TestChangeState(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "change state with invalid token",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: invalidToken,
|
||||
state: active,
|
||||
contentType: contentType,
|
||||
@@ -1306,7 +1306,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state with an empty token",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: "",
|
||||
state: active,
|
||||
contentType: contentType,
|
||||
@@ -1315,7 +1315,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state with invalid content type",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
state: active,
|
||||
contentType: "",
|
||||
@@ -1324,7 +1324,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state to active",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
state: active,
|
||||
contentType: contentType,
|
||||
@@ -1333,7 +1333,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state to inactive",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
state: inactive,
|
||||
contentType: contentType,
|
||||
@@ -1351,7 +1351,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state to invalid value",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
state: fmt.Sprintf("{\"state\": %d}", -3),
|
||||
contentType: contentType,
|
||||
@@ -1360,7 +1360,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state with invalid data",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
state: "",
|
||||
contentType: contentType,
|
||||
@@ -1379,7 +1379,7 @@ func TestChangeState(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: bs.Client(),
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%s/things/state/%s", bs.URL, domainID, tc.id),
|
||||
url: fmt.Sprintf("%s/%s/clients/state/%s", bs.URL, domainID, tc.id),
|
||||
token: tc.token,
|
||||
contentType: tc.contentType,
|
||||
body: strings.NewReader(tc.state),
|
||||
@@ -1400,14 +1400,14 @@ type channel struct {
|
||||
}
|
||||
|
||||
type config struct {
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ThingKey string `json:"thing_key,omitempty"`
|
||||
Channels []channel `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Name string `json:"name"`
|
||||
State bootstrap.State `json:"state"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
ClientSecret string `json:"client_secret,omitempty"`
|
||||
Channels []channel `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Name string `json:"name"`
|
||||
State bootstrap.State `json:"state"`
|
||||
}
|
||||
|
||||
type configPage struct {
|
||||
|
||||
@@ -12,7 +12,7 @@ const maxLimitSize = 100
|
||||
|
||||
type addReq struct {
|
||||
token string
|
||||
ThingID string `json:"thing_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key"`
|
||||
Channels []string `json:"channels"`
|
||||
@@ -76,14 +76,14 @@ func (req updateReq) validate() error {
|
||||
}
|
||||
|
||||
type updateCertReq struct {
|
||||
thingID string
|
||||
clientID string
|
||||
ClientCert string `json:"client_cert"`
|
||||
ClientKey string `json:"client_key"`
|
||||
CACert string `json:"ca_cert"`
|
||||
}
|
||||
|
||||
func (req updateCertReq) validate() error {
|
||||
if req.thingID == "" {
|
||||
if req.clientID == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
|
||||
@@ -151,20 +151,20 @@ func TestUpdateReqValidation(t *testing.T) {
|
||||
|
||||
func TestUpdateCertReqValidation(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
err error
|
||||
desc string
|
||||
clientID string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "empty thing id",
|
||||
thingID: "",
|
||||
err: apiutil.ErrMissingID,
|
||||
desc: "empty client id",
|
||||
clientID: "",
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
req := updateCertReq{
|
||||
thingID: tc.thingID,
|
||||
clientID: tc.clientID,
|
||||
}
|
||||
|
||||
err := req.validate()
|
||||
|
||||
+13
-13
@@ -49,7 +49,7 @@ func (res configRes) Code() int {
|
||||
func (res configRes) Headers() map[string]string {
|
||||
if res.created {
|
||||
return map[string]string{
|
||||
"Location": fmt.Sprintf("/things/configs/%s", res.id),
|
||||
"Location": fmt.Sprintf("/clients/configs/%s", res.id),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,16 +67,16 @@ type channelRes struct {
|
||||
}
|
||||
|
||||
type viewRes struct {
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ThingKey string `json:"thing_key,omitempty"`
|
||||
Channels []channelRes `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
State bootstrap.State `json:"state"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
CLientSecret string `json:"client_secret,omitempty"`
|
||||
Channels []channelRes `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
State bootstrap.State `json:"state"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
}
|
||||
|
||||
func (res viewRes) Code() int {
|
||||
@@ -125,9 +125,9 @@ func (res stateRes) Empty() bool {
|
||||
}
|
||||
|
||||
type updateConfigRes struct {
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
fullMatch = []string{"state", "external_id", "thing_id", "thing_key"}
|
||||
fullMatch = []string{"state", "external_id", "client_id", "client_key"}
|
||||
partialMatch = []string{"name"}
|
||||
// ErrBootstrap indicates error in getting bootstrap configuration.
|
||||
ErrBootstrap = errors.New("failed to read bootstrap configuration")
|
||||
@@ -47,7 +47,7 @@ func MakeHandler(svc bootstrap.Service, authn mgauthn.Authentication, reader boo
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Route("/{domainID}/things", func(r chi.Router) {
|
||||
r.Route("/{domainID}/clients", func(r chi.Router) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(api.AuthenticateMiddleware(authn, true))
|
||||
|
||||
@@ -96,14 +96,14 @@ func MakeHandler(svc bootstrap.Service, authn mgauthn.Authentication, reader boo
|
||||
})
|
||||
})
|
||||
|
||||
r.With(api.AuthenticateMiddleware(authn, true)).Put("/state/{thingID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
r.With(api.AuthenticateMiddleware(authn, true)).Put("/state/{clientID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
stateEndpoint(svc),
|
||||
decodeStateRequest,
|
||||
api.EncodeResponse,
|
||||
opts...), "update_state").ServeHTTP)
|
||||
})
|
||||
|
||||
r.Route("/things/bootstrap", func(r chi.Router) {
|
||||
r.Route("/clients/bootstrap", func(r chi.Router) {
|
||||
r.Get("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
bootstrapEndpoint(svc, reader, false),
|
||||
decodeBootstrapRequest,
|
||||
@@ -163,7 +163,7 @@ func decodeUpdateCertRequest(_ context.Context, r *http.Request) (interface{}, e
|
||||
}
|
||||
|
||||
req := updateCertReq{
|
||||
thingID: chi.URLParam(r, "certID"),
|
||||
clientID: chi.URLParam(r, "certID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
||||
@@ -216,7 +216,7 @@ func decodeListRequest(_ context.Context, r *http.Request) (interface{}, error)
|
||||
func decodeBootstrapRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := bootstrapReq{
|
||||
id: chi.URLParam(r, "externalID"),
|
||||
key: apiutil.ExtractThingKey(r),
|
||||
key: apiutil.ExtractClientSecret(r),
|
||||
}
|
||||
|
||||
return req, nil
|
||||
@@ -229,7 +229,7 @@ func decodeStateRequest(_ context.Context, r *http.Request) (interface{}, error)
|
||||
|
||||
req := changeStateReq{
|
||||
token: apiutil.ExtractBearerToken(r),
|
||||
id: chi.URLParam(r, "thingID"),
|
||||
id: chi.URLParam(r, "clientID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
||||
|
||||
+27
-27
@@ -7,30 +7,30 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/things"
|
||||
"github.com/absmach/magistrala/clients"
|
||||
)
|
||||
|
||||
// Config represents Configuration entity. It wraps information about external entity
|
||||
// as well as info about corresponding Magistrala entities.
|
||||
// MGThing represents corresponding Magistrala Thing ID.
|
||||
// MGKey is key of corresponding Magistrala Thing.
|
||||
// MGChannels is a list of Magistrala Channels corresponding Magistrala Thing connects to.
|
||||
// MGClient represents corresponding Magistrala Client ID.
|
||||
// MGKey is key of corresponding Magistrala Client.
|
||||
// MGChannels is a list of Magistrala Channels corresponding Magistrala Client connects to.
|
||||
type Config struct {
|
||||
ThingID string `json:"thing_id"`
|
||||
DomainID string `json:"domain_id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []Channel `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key"`
|
||||
Content string `json:"content,omitempty"`
|
||||
State State `json:"state"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
DomainID string `json:"domain_id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
Channels []Channel `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key"`
|
||||
Content string `json:"content,omitempty"`
|
||||
State State `json:"state"`
|
||||
}
|
||||
|
||||
// Channel represents Magistrala channel corresponding Magistrala Thing is connected to.
|
||||
// Channel represents Magistrala channel corresponding Magistrala Client is connected to.
|
||||
type Channel struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
@@ -41,7 +41,7 @@ type Channel struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
UpdatedBy string `json:"updated_by,omitempty"`
|
||||
Status things.Status `json:"status"`
|
||||
Status clients.Status `json:"status"`
|
||||
}
|
||||
|
||||
// Filter is used for the search filters.
|
||||
@@ -73,7 +73,7 @@ type ConfigRepository interface {
|
||||
|
||||
// RetrieveAll retrieves a subset of Configs that are owned
|
||||
// by the specific user, with given filter parameters.
|
||||
RetrieveAll(ctx context.Context, domainID string, thingIDs []string, filter Filter, offset, limit uint64) ConfigsPage
|
||||
RetrieveAll(ctx context.Context, domainID string, clientIDs []string, filter Filter, offset, limit uint64) ConfigsPage
|
||||
|
||||
// RetrieveByExternalID returns Config for given external ID.
|
||||
RetrieveByExternalID(ctx context.Context, externalID string) (Config, error)
|
||||
@@ -84,7 +84,7 @@ type ConfigRepository interface {
|
||||
|
||||
// UpdateCerts updates and returns an existing Config certificate and domainID.
|
||||
// A non-nil error is returned to indicate operation failure.
|
||||
UpdateCert(ctx context.Context, domainID, thingID, clientCert, clientKey, caCert string) (Config, error)
|
||||
UpdateCert(ctx context.Context, domainID, clientID, clientCert, clientKey, caCert string) (Config, error)
|
||||
|
||||
// UpdateConnections updates a list of Channels the Config is connected to
|
||||
// adding new Channels if needed.
|
||||
@@ -100,11 +100,11 @@ type ConfigRepository interface {
|
||||
// ListExisting retrieves those channels from the given list that exist in DB.
|
||||
ListExisting(ctx context.Context, domainID string, ids []string) ([]Channel, error)
|
||||
|
||||
// Methods RemoveThing, UpdateChannel, and RemoveChannel are related to
|
||||
// Methods RemoveClient, UpdateChannel, and RemoveChannel are related to
|
||||
// event sourcing. That's why these methods surpass ownership check.
|
||||
|
||||
// RemoveThing removes Config of the Thing with the given ID.
|
||||
RemoveThing(ctx context.Context, id string) error
|
||||
// RemoveClient removes Config of the Client with the given ID.
|
||||
RemoveClient(ctx context.Context, id string) error
|
||||
|
||||
// UpdateChannel updates channel with the given ID.
|
||||
UpdateChannel(ctx context.Context, c Channel) error
|
||||
@@ -112,9 +112,9 @@ type ConfigRepository interface {
|
||||
// RemoveChannel removes channel with the given ID.
|
||||
RemoveChannel(ctx context.Context, id string) error
|
||||
|
||||
// ConnectThing changes state of the Config when the corresponding Thing is connected to the Channel.
|
||||
ConnectThing(ctx context.Context, channelID, thingID string) error
|
||||
// ConnectClient changes state of the Config when the corresponding Client is connected to the Channel.
|
||||
ConnectClient(ctx context.Context, channelID, clientID string) error
|
||||
|
||||
// DisconnectThing changes state of the Config when the corresponding Thing is disconnected from the Channel.
|
||||
DisconnectThing(ctx context.Context, channelID, thingID string) error
|
||||
// DisconnectClient changes state of the Config when the corresponding Client is disconnected from the Channel.
|
||||
DisconnectClient(ctx context.Context, channelID, clientID string) error
|
||||
}
|
||||
|
||||
@@ -19,6 +19,6 @@ type updateChannelEvent struct {
|
||||
|
||||
// Connection event is either connect or disconnect event.
|
||||
type connectionEvent struct {
|
||||
thingIDs []string
|
||||
clientIDs []string
|
||||
channelID string
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
thingRemove = "thing.remove"
|
||||
thingConnect = "group.assign"
|
||||
thingDisconnect = "group.unassign"
|
||||
clientRemove = "client.remove"
|
||||
clientConnect = "group.assign"
|
||||
clientDisconnect = "group.unassign"
|
||||
|
||||
channelPrefix = "group."
|
||||
channelPrefix = "channels."
|
||||
channelUpdate = channelPrefix + "update"
|
||||
channelRemove = channelPrefix + "remove"
|
||||
|
||||
memberKind = "things"
|
||||
memberKind = "client"
|
||||
relation = "group"
|
||||
)
|
||||
|
||||
@@ -43,35 +43,35 @@ func (es *eventHandler) Handle(ctx context.Context, event events.Event) error {
|
||||
}
|
||||
|
||||
switch msg["operation"] {
|
||||
case thingRemove:
|
||||
rte := decodeRemoveThing(msg)
|
||||
case clientRemove:
|
||||
rte := decodeRemoveClient(msg)
|
||||
err = es.svc.RemoveConfigHandler(ctx, rte.id)
|
||||
case thingConnect:
|
||||
cte := decodeConnectThing(msg)
|
||||
if cte.channelID == "" || len(cte.thingIDs) == 0 {
|
||||
case clientConnect:
|
||||
cte := decodeConnectClient(msg)
|
||||
if cte.channelID == "" || len(cte.clientIDs) == 0 {
|
||||
return svcerr.ErrMalformedEntity
|
||||
}
|
||||
for _, thingID := range cte.thingIDs {
|
||||
if thingID == "" {
|
||||
for _, clientID := range cte.clientIDs {
|
||||
if clientID == "" {
|
||||
return svcerr.ErrMalformedEntity
|
||||
}
|
||||
if err := es.svc.ConnectThingHandler(ctx, cte.channelID, thingID); err != nil {
|
||||
if err := es.svc.ConnectClientHandler(ctx, cte.channelID, clientID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case thingDisconnect:
|
||||
dte := decodeDisconnectThing(msg)
|
||||
if dte.channelID == "" || len(dte.thingIDs) == 0 {
|
||||
case clientDisconnect:
|
||||
dte := decodeDisconnectClient(msg)
|
||||
if dte.channelID == "" || len(dte.clientIDs) == 0 {
|
||||
return svcerr.ErrMalformedEntity
|
||||
}
|
||||
for _, thingID := range dte.thingIDs {
|
||||
if thingID == "" {
|
||||
for _, clientID := range dte.clientIDs {
|
||||
if clientID == "" {
|
||||
return svcerr.ErrMalformedEntity
|
||||
}
|
||||
}
|
||||
|
||||
for _, thingID := range dte.thingIDs {
|
||||
if err = es.svc.DisconnectThingHandler(ctx, dte.channelID, thingID); err != nil {
|
||||
for _, c := range dte.clientIDs {
|
||||
if err = es.svc.DisconnectClientHandler(ctx, dte.channelID, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (es *eventHandler) Handle(ctx context.Context, event events.Event) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeRemoveThing(event map[string]interface{}) removeEvent {
|
||||
func decodeRemoveClient(event map[string]interface{}) removeEvent {
|
||||
return removeEvent{
|
||||
id: events.Read(event, "id", ""),
|
||||
}
|
||||
@@ -113,25 +113,25 @@ func decodeRemoveChannel(event map[string]interface{}) removeEvent {
|
||||
}
|
||||
}
|
||||
|
||||
func decodeConnectThing(event map[string]interface{}) connectionEvent {
|
||||
func decodeConnectClient(event map[string]interface{}) connectionEvent {
|
||||
if events.Read(event, "memberKind", "") != memberKind && events.Read(event, "relation", "") != relation {
|
||||
return connectionEvent{}
|
||||
}
|
||||
|
||||
return connectionEvent{
|
||||
channelID: events.Read(event, "group_id", ""),
|
||||
thingIDs: events.ReadStringSlice(event, "member_ids"),
|
||||
clientIDs: events.ReadStringSlice(event, "member_ids"),
|
||||
}
|
||||
}
|
||||
|
||||
func decodeDisconnectThing(event map[string]interface{}) connectionEvent {
|
||||
func decodeDisconnectClient(event map[string]interface{}) connectionEvent {
|
||||
if events.Read(event, "memberKind", "") != memberKind && events.Read(event, "relation", "") != relation {
|
||||
return connectionEvent{}
|
||||
}
|
||||
|
||||
return connectionEvent{
|
||||
channelID: events.Read(event, "group_id", ""),
|
||||
thingIDs: events.ReadStringSlice(event, "member_ids"),
|
||||
clientIDs: events.ReadStringSlice(event, "member_ids"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ const (
|
||||
configList = configPrefix + "list"
|
||||
configHandlerRemove = configPrefix + "remove_handler"
|
||||
|
||||
thingPrefix = "bootstrap.thing."
|
||||
thingBootstrap = thingPrefix + "bootstrap"
|
||||
thingStateChange = thingPrefix + "change_state"
|
||||
thingUpdateConnections = thingPrefix + "update_connections"
|
||||
thingConnect = thingPrefix + "connect"
|
||||
thingDisconnect = thingPrefix + "disconnect"
|
||||
clientPrefix = "bootstrap.client."
|
||||
clientBootstrap = clientPrefix + "bootstrap"
|
||||
clientStateChange = clientPrefix + "change_state"
|
||||
clientUpdateConnections = clientPrefix + "update_connections"
|
||||
clientConnect = clientPrefix + "connect"
|
||||
clientDisconnect = clientPrefix + "disconnect"
|
||||
|
||||
channelPrefix = "bootstrap.channel."
|
||||
channelHandlerRemove = channelPrefix + "remove_handler"
|
||||
@@ -52,8 +52,8 @@ func (ce configEvent) Encode() (map[string]interface{}, error) {
|
||||
"state": ce.State.String(),
|
||||
"operation": ce.operation,
|
||||
}
|
||||
if ce.ThingID != "" {
|
||||
val["thing_id"] = ce.ThingID
|
||||
if ce.ClientID != "" {
|
||||
val["client_id"] = ce.ClientID
|
||||
}
|
||||
if ce.Content != "" {
|
||||
val["content"] = ce.Content
|
||||
@@ -91,12 +91,12 @@ func (ce configEvent) Encode() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
type removeConfigEvent struct {
|
||||
mgThing string
|
||||
client string
|
||||
}
|
||||
|
||||
func (rce removeConfigEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"thing_id": rce.mgThing,
|
||||
"client_id": rce.client,
|
||||
"operation": configRemove,
|
||||
}, nil
|
||||
}
|
||||
@@ -134,11 +134,11 @@ func (be bootstrapEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"external_id": be.externalID,
|
||||
"success": be.success,
|
||||
"operation": thingBootstrap,
|
||||
"operation": clientBootstrap,
|
||||
}
|
||||
|
||||
if be.ThingID != "" {
|
||||
val["thing_id"] = be.ThingID
|
||||
if be.ClientID != "" {
|
||||
val["client_id"] = be.ClientID
|
||||
}
|
||||
if be.Content != "" {
|
||||
val["content"] = be.Content
|
||||
@@ -175,38 +175,41 @@ func (be bootstrapEvent) Encode() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
type changeStateEvent struct {
|
||||
mgThing string
|
||||
state bootstrap.State
|
||||
mgClient string
|
||||
state bootstrap.State
|
||||
}
|
||||
|
||||
func (cse changeStateEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"thing_id": cse.mgThing,
|
||||
"client_id": cse.mgClient,
|
||||
"state": cse.state.String(),
|
||||
"operation": thingStateChange,
|
||||
"operation": clientStateChange,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type updateConnectionsEvent struct {
|
||||
mgThing string
|
||||
mgClient string
|
||||
mgChannels []string
|
||||
}
|
||||
|
||||
func (uce updateConnectionsEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"thing_id": uce.mgThing,
|
||||
"client_id": uce.mgClient,
|
||||
"channels": uce.mgChannels,
|
||||
"operation": thingUpdateConnections,
|
||||
"operation": clientUpdateConnections,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type updateCertEvent struct {
|
||||
thingKey, clientCert, clientKey, caCert string
|
||||
clientID string
|
||||
clientCert string
|
||||
clientKey string
|
||||
caCert string
|
||||
}
|
||||
|
||||
func (uce updateCertEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"thing_key": uce.thingKey,
|
||||
"client_id": uce.clientID,
|
||||
"client_cert": uce.clientCert,
|
||||
"client_key": uce.clientKey,
|
||||
"ca_cert": uce.caCert,
|
||||
@@ -247,28 +250,28 @@ func (uche updateChannelHandlerEvent) Encode() (map[string]interface{}, error) {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
type connectThingEvent struct {
|
||||
thingID string
|
||||
type connectClientEvent struct {
|
||||
clientID string
|
||||
channelID string
|
||||
}
|
||||
|
||||
func (cte connectThingEvent) Encode() (map[string]interface{}, error) {
|
||||
func (cte connectClientEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"thing_id": cte.thingID,
|
||||
"client_id": cte.clientID,
|
||||
"channel_id": cte.channelID,
|
||||
"operation": thingConnect,
|
||||
"operation": clientConnect,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type disconnectThingEvent struct {
|
||||
thingID string
|
||||
type disconnectClientEvent struct {
|
||||
clientID string
|
||||
channelID string
|
||||
}
|
||||
|
||||
func (dte disconnectThingEvent) Encode() (map[string]interface{}, error) {
|
||||
func (dte disconnectClientEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"thing_id": dte.thingID,
|
||||
"client_id": dte.clientID,
|
||||
"channel_id": dte.channelID,
|
||||
"operation": thingDisconnect,
|
||||
"operation": clientDisconnect,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -72,14 +72,14 @@ func (es *eventStore) Update(ctx context.Context, session mgauthn.Session, cfg b
|
||||
return es.Publish(ctx, ev)
|
||||
}
|
||||
|
||||
func (es eventStore) UpdateCert(ctx context.Context, session mgauthn.Session, thingKey, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
cfg, err := es.svc.UpdateCert(ctx, session, thingKey, clientCert, clientKey, caCert)
|
||||
func (es eventStore) UpdateCert(ctx context.Context, session mgauthn.Session, clientID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
cfg, err := es.svc.UpdateCert(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
ev := updateCertEvent{
|
||||
thingKey: thingKey,
|
||||
clientID: clientID,
|
||||
clientCert: clientCert,
|
||||
clientKey: clientKey,
|
||||
caCert: caCert,
|
||||
@@ -98,7 +98,7 @@ func (es *eventStore) UpdateConnections(ctx context.Context, session mgauthn.Ses
|
||||
}
|
||||
|
||||
ev := updateConnectionsEvent{
|
||||
mgThing: id,
|
||||
mgClient: id,
|
||||
mgChannels: connections,
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ func (es *eventStore) Remove(ctx context.Context, session mgauthn.Session, id st
|
||||
}
|
||||
|
||||
ev := removeConfigEvent{
|
||||
mgThing: id,
|
||||
client: id,
|
||||
}
|
||||
|
||||
return es.Publish(ctx, ev)
|
||||
@@ -163,8 +163,8 @@ func (es *eventStore) ChangeState(ctx context.Context, session mgauthn.Session,
|
||||
}
|
||||
|
||||
ev := changeStateEvent{
|
||||
mgThing: id,
|
||||
state: state,
|
||||
mgClient: id,
|
||||
state: state,
|
||||
}
|
||||
|
||||
return es.Publish(ctx, ev)
|
||||
@@ -208,26 +208,26 @@ func (es *eventStore) UpdateChannelHandler(ctx context.Context, channel bootstra
|
||||
return es.Publish(ctx, ev)
|
||||
}
|
||||
|
||||
func (es *eventStore) ConnectThingHandler(ctx context.Context, channelID, thingID string) error {
|
||||
if err := es.svc.ConnectThingHandler(ctx, channelID, thingID); err != nil {
|
||||
func (es *eventStore) ConnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
if err := es.svc.ConnectClientHandler(ctx, channelID, clientID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ev := connectThingEvent{
|
||||
thingID: thingID,
|
||||
ev := connectClientEvent{
|
||||
clientID: clientID,
|
||||
channelID: channelID,
|
||||
}
|
||||
|
||||
return es.Publish(ctx, ev)
|
||||
}
|
||||
|
||||
func (es *eventStore) DisconnectThingHandler(ctx context.Context, channelID, thingID string) error {
|
||||
if err := es.svc.DisconnectThingHandler(ctx, channelID, thingID); err != nil {
|
||||
func (es *eventStore) DisconnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
if err := es.svc.DisconnectClientHandler(ctx, channelID, clientID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ev := disconnectThingEvent{
|
||||
thingID: thingID,
|
||||
ev := disconnectClientEvent{
|
||||
clientID: clientID,
|
||||
channelID: channelID,
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/bootstrap"
|
||||
"github.com/absmach/magistrala/bootstrap/events/producer"
|
||||
"github.com/absmach/magistrala/bootstrap/mocks"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
"github.com/absmach/magistrala/pkg/authn"
|
||||
mgauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
@@ -32,13 +32,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
streamID = "magistrala.bootstrap"
|
||||
email = "user@example.com"
|
||||
validToken = "validToken"
|
||||
invalidToken = "invalid"
|
||||
unknownThingID = "unknown"
|
||||
channelsNum = 3
|
||||
defaultTimout = 5
|
||||
streamID = "magistrala.bootstrap"
|
||||
email = "user@example.com"
|
||||
validToken = "validToken"
|
||||
invalidToken = "invalid"
|
||||
unknownClientID = "unknown"
|
||||
channelsNum = 3
|
||||
defaultTimout = 5
|
||||
|
||||
configPrefix = "config."
|
||||
configCreate = configPrefix + "create"
|
||||
@@ -48,12 +48,12 @@ const (
|
||||
configList = configPrefix + "list"
|
||||
configHandlerRemove = configPrefix + "remove_handler"
|
||||
|
||||
thingPrefix = "thing."
|
||||
thingBootstrap = thingPrefix + "bootstrap"
|
||||
thingStateChange = thingPrefix + "change_state"
|
||||
thingUpdateConnections = thingPrefix + "update_connections"
|
||||
thingConnect = thingPrefix + "connect"
|
||||
thingDisconnect = thingPrefix + "disconnect"
|
||||
clientPrefix = "client."
|
||||
clientBootstrap = clientPrefix + "bootstrap"
|
||||
clientStateChange = clientPrefix + "change_state"
|
||||
clientUpdateConnections = clientPrefix + "update_connections"
|
||||
clientConnect = clientPrefix + "connect"
|
||||
clientDisconnect = clientPrefix + "disconnect"
|
||||
|
||||
channelPrefix = "group."
|
||||
channelHandlerRemove = channelPrefix + "remove_handler"
|
||||
@@ -76,12 +76,12 @@ var (
|
||||
}
|
||||
|
||||
config = bootstrap.Config{
|
||||
ThingID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ThingKey: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalKey: testsutil.GenerateUUID(&testing.T{}),
|
||||
Channels: []bootstrap.Channel{channel},
|
||||
Content: "config",
|
||||
ClientID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ClientSecret: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalKey: testsutil.GenerateUUID(&testing.T{}),
|
||||
Channels: []bootstrap.Channel{channel},
|
||||
Content: "config",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -125,18 +125,18 @@ func TestAdd(t *testing.T) {
|
||||
invalidConfig.Channels = []bootstrap.Channel{{ID: "empty"}}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
config bootstrap.Config
|
||||
token string
|
||||
session mgauthn.Session
|
||||
id string
|
||||
domainID string
|
||||
thingErr error
|
||||
channel []bootstrap.Channel
|
||||
listErr error
|
||||
saveErr error
|
||||
err error
|
||||
event map[string]interface{}
|
||||
desc string
|
||||
config bootstrap.Config
|
||||
token string
|
||||
session mgauthn.Session
|
||||
id string
|
||||
domainID string
|
||||
clientErr error
|
||||
channel []bootstrap.Channel
|
||||
listErr error
|
||||
saveErr error
|
||||
err error
|
||||
event map[string]interface{}
|
||||
}{
|
||||
{
|
||||
desc: "create config successfully",
|
||||
@@ -146,7 +146,7 @@ func TestAdd(t *testing.T) {
|
||||
domainID: domainID,
|
||||
channel: config.Channels,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": "1",
|
||||
"client_id": "1",
|
||||
"domain_id": domainID,
|
||||
"name": config.Name,
|
||||
"channels": channels,
|
||||
@@ -158,14 +158,14 @@ func TestAdd(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "create config with failed to fetch thing",
|
||||
config: config,
|
||||
token: validToken,
|
||||
id: validID,
|
||||
domainID: domainID,
|
||||
event: nil,
|
||||
thingErr: svcerr.ErrNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
desc: "create config with failed to fetch client",
|
||||
config: config,
|
||||
token: validToken,
|
||||
id: validID,
|
||||
domainID: domainID,
|
||||
event: nil,
|
||||
clientErr: svcerr.ErrNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "create config with failed to list existing",
|
||||
@@ -192,7 +192,7 @@ func TestAdd(t *testing.T) {
|
||||
lastID := "0"
|
||||
for _, tc := range cases {
|
||||
tc.session = mgauthn.Session{UserID: validID, DomainID: tc.domainID, DomainUserID: validID}
|
||||
sdkCall := tv.sdk.On("Thing", tc.config.ThingID, tc.domainID, tc.token).Return(mgsdk.Thing{ID: tc.config.ThingID, Credentials: mgsdk.ClientCredentials{Secret: tc.config.ThingKey}}, errors.NewSDKError(tc.thingErr))
|
||||
sdkCall := tv.sdk.On("Client", tc.config.ClientID, tc.domainID, tc.token).Return(mgsdk.Client{ID: tc.config.ClientID, Credentials: mgsdk.ClientCredentials{Secret: tc.config.ClientSecret}}, errors.NewSDKError(tc.clientErr))
|
||||
repoCall := tv.boot.On("ListExisting", context.Background(), domainID, mock.Anything).Return(tc.config.Channels, tc.listErr)
|
||||
repoCall1 := tv.boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, tc.saveErr)
|
||||
|
||||
@@ -226,7 +226,7 @@ func TestView(t *testing.T) {
|
||||
tv := newTestVariable(t, redisURL)
|
||||
|
||||
nonExisting := config
|
||||
nonExisting.ThingID = unknownThingID
|
||||
nonExisting.ClientID = unknownClientID
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -247,7 +247,7 @@ func TestView(t *testing.T) {
|
||||
domainID: domainID,
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": config.ThingID,
|
||||
"client_id": config.ClientID,
|
||||
"domain_id": config.DomainID,
|
||||
"name": config.Name,
|
||||
"channels": config.Channels,
|
||||
@@ -272,8 +272,8 @@ func TestView(t *testing.T) {
|
||||
lastID := "0"
|
||||
for _, tc := range cases {
|
||||
tc.session = mgauthn.Session{UserID: validID, DomainID: tc.domainID, DomainUserID: validID}
|
||||
repoCall := tv.boot.On("RetrieveByID", context.Background(), tc.domainID, tc.config.ThingID).Return(config, tc.retrieveErr)
|
||||
_, err := tv.svc.View(context.Background(), tc.session, tc.config.ThingID)
|
||||
repoCall := tv.boot.On("RetrieveByID", context.Background(), tc.domainID, tc.config.ClientID).Return(config, tc.retrieveErr)
|
||||
_, err := tv.svc.View(context.Background(), tc.session, tc.config.ClientID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
|
||||
streams := redisClient.XRead(context.Background(), &redis.XReadArgs{
|
||||
@@ -316,7 +316,7 @@ func TestUpdate(t *testing.T) {
|
||||
modified.Name = "new name"
|
||||
|
||||
nonExisting := config
|
||||
nonExisting.ThingID = unknownThingID
|
||||
nonExisting.ClientID = unknownClientID
|
||||
|
||||
channels := []string{modified.Channels[0].ID, modified.Channels[1].ID}
|
||||
|
||||
@@ -345,7 +345,7 @@ func TestUpdate(t *testing.T) {
|
||||
"operation": configUpdate,
|
||||
"channels": channels,
|
||||
"external_id": modified.ExternalID,
|
||||
"thing_id": modified.ThingID,
|
||||
"client_id": modified.ClientID,
|
||||
"domain_id": domainID,
|
||||
"state": "0",
|
||||
"occurred_at": time.Now().UnixNano(),
|
||||
@@ -403,7 +403,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
token string
|
||||
session mgauthn.Session
|
||||
connections []string
|
||||
thingErr error
|
||||
clientErr error
|
||||
channelErr error
|
||||
retrieveErr error
|
||||
listErr error
|
||||
@@ -413,22 +413,22 @@ func TestUpdateConnections(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "update connections successfully",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
id: validID,
|
||||
domainID: domainID,
|
||||
connections: []string{config.Channels[0].ID},
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": config.ThingID,
|
||||
"client_id": config.ClientID,
|
||||
"channels": "2",
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": thingUpdateConnections,
|
||||
"operation": clientUpdateConnections,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "update connections with failed channel fetch",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
id: validID,
|
||||
domainID: domainID,
|
||||
@@ -439,7 +439,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update connections with failed RetrieveByID",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
id: validID,
|
||||
domainID: domainID,
|
||||
@@ -450,7 +450,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update connections with failed ListExisting",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
id: validID,
|
||||
domainID: domainID,
|
||||
@@ -461,7 +461,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update connections with failed UpdateConnections",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
id: validID,
|
||||
domainID: domainID,
|
||||
@@ -524,7 +524,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "update cert successfully",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
token: validToken,
|
||||
@@ -533,16 +533,16 @@ func TestUpdateCert(t *testing.T) {
|
||||
caCert: "caCert",
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_key": config.ThingKey,
|
||||
"client_cert": "clientCert",
|
||||
"client_key": "clientKey",
|
||||
"ca_cert": "caCert",
|
||||
"operation": certUpdate,
|
||||
"client_secret": config.ClientSecret,
|
||||
"client_cert": "clientCert",
|
||||
"client_key": "clientKey",
|
||||
"ca_cert": "caCert",
|
||||
"operation": certUpdate,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "update cert with failed update",
|
||||
configID: "invalidThingID",
|
||||
configID: "clientID",
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -555,7 +555,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update cert with empty client certificate",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -567,7 +567,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update cert with empty client key",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -579,7 +579,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update cert with empty CA certificate",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -591,7 +591,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "successful update without CA certificate",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -600,12 +600,12 @@ func TestUpdateCert(t *testing.T) {
|
||||
caCert: "",
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_key": config.ThingKey,
|
||||
"client_cert": "clientCert",
|
||||
"client_key": "clientKey",
|
||||
"ca_cert": "caCert",
|
||||
"operation": certUpdate,
|
||||
"timestamp": time.Now().Unix(),
|
||||
"client_secret": config.ClientSecret,
|
||||
"client_cert": "clientCert",
|
||||
"client_key": "clientKey",
|
||||
"ca_cert": "caCert",
|
||||
"operation": certUpdate,
|
||||
"timestamp": time.Now().Unix(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -639,10 +639,10 @@ func TestUpdateCert(t *testing.T) {
|
||||
func TestList(t *testing.T) {
|
||||
tv := newTestVariable(t, redisURL)
|
||||
|
||||
numThings := 101
|
||||
numClients := 101
|
||||
var c bootstrap.Config
|
||||
saved := make([]bootstrap.Config, 0)
|
||||
for i := 0; i < numThings; i++ {
|
||||
for i := 0; i < numClients; i++ {
|
||||
c := config
|
||||
c.ExternalID = testsutil.GenerateUUID(t)
|
||||
c.ExternalKey = testsutil.GenerateUUID(t)
|
||||
@@ -687,7 +687,7 @@ func TestList(t *testing.T) {
|
||||
listObjectsResponse: policysvc.PolicyPage{},
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": c.ThingID,
|
||||
"client_id": c.ClientID,
|
||||
"domain_id": c.DomainID,
|
||||
"name": c.Name,
|
||||
"channels": c.Channels,
|
||||
@@ -715,7 +715,7 @@ func TestList(t *testing.T) {
|
||||
listObjectsResponse: policysvc.PolicyPage{},
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": c.ThingID,
|
||||
"client_id": c.ClientID,
|
||||
"domain_id": c.DomainID,
|
||||
"name": c.Name,
|
||||
"channels": c.Channels,
|
||||
@@ -743,7 +743,7 @@ func TestList(t *testing.T) {
|
||||
listObjectsResponse: policysvc.PolicyPage{},
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": c.ThingID,
|
||||
"client_id": c.ClientID,
|
||||
"domain_id": c.DomainID,
|
||||
"name": c.Name,
|
||||
"channels": c.Channels,
|
||||
@@ -818,7 +818,7 @@ func TestList(t *testing.T) {
|
||||
SubjectType: policysvc.UserType,
|
||||
Subject: tc.userID,
|
||||
Permission: policysvc.ViewPermission,
|
||||
ObjectType: policysvc.ThingType,
|
||||
ObjectType: policysvc.ClientType,
|
||||
}).Return(tc.listObjectsResponse, tc.listObjectsErr)
|
||||
repoCall := tv.boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, tc.filter, tc.offset, tc.limit).Return(tc.config, tc.retrieveErr)
|
||||
|
||||
@@ -851,7 +851,7 @@ func TestRemove(t *testing.T) {
|
||||
tv := newTestVariable(t, redisURL)
|
||||
|
||||
nonExisting := config
|
||||
nonExisting.ThingID = unknownThingID
|
||||
nonExisting.ClientID = unknownClientID
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -866,20 +866,20 @@ func TestRemove(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "remove config successfully",
|
||||
configID: config.ThingID,
|
||||
configID: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": config.ThingID,
|
||||
"client_id": config.ClientID,
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": configRemove,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "remove config with failed removal",
|
||||
configID: nonExisting.ThingID,
|
||||
configID: nonExisting.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -936,7 +936,7 @@ func TestBootstrap(t *testing.T) {
|
||||
"external_id": config.ExternalID,
|
||||
"success": "1",
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": thingBootstrap,
|
||||
"operation": clientBootstrap,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -949,7 +949,7 @@ func TestBootstrap(t *testing.T) {
|
||||
"external_id": "external_id",
|
||||
"success": "0",
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": thingBootstrap,
|
||||
"operation": clientBootstrap,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -990,7 +990,7 @@ func TestChangeState(t *testing.T) {
|
||||
token string
|
||||
session mgauthn.Session
|
||||
state bootstrap.State
|
||||
authResponse *magistrala.AuthZRes
|
||||
authResponse authn.Session
|
||||
authorizeErr error
|
||||
connectErr error
|
||||
retrieveErr error
|
||||
@@ -1001,18 +1001,18 @@ func TestChangeState(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "change state to active",
|
||||
id: config.ThingID,
|
||||
id: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
state: bootstrap.Active,
|
||||
authResponse: &magistrala.AuthZRes{Authorized: true},
|
||||
authResponse: authn.Session{},
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": config.ThingID,
|
||||
"client_id": config.ClientID,
|
||||
"state": bootstrap.Active.String(),
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": thingStateChange,
|
||||
"operation": clientStateChange,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1028,18 +1028,18 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state with failed connect",
|
||||
id: config.ThingID,
|
||||
id: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
state: bootstrap.Active,
|
||||
connectErr: bootstrap.ErrThings,
|
||||
err: bootstrap.ErrThings,
|
||||
connectErr: bootstrap.ErrClients,
|
||||
err: bootstrap.ErrClients,
|
||||
event: nil,
|
||||
},
|
||||
{
|
||||
desc: "change state unsuccessfully",
|
||||
id: config.ThingID,
|
||||
id: config.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -1054,7 +1054,7 @@ func TestChangeState(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
tc.session = mgauthn.Session{UserID: validID, DomainID: tc.domainID, DomainUserID: validID}
|
||||
repoCall := tv.boot.On("RetrieveByID", context.Background(), tc.domainID, tc.id).Return(config, tc.retrieveErr)
|
||||
sdkCall1 := tv.sdk.On("Connect", mock.Anything, mock.Anything, mock.Anything).Return(errors.NewSDKError(tc.connectErr))
|
||||
sdkCall1 := tv.sdk.On("ConnectClient", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.NewSDKError(tc.connectErr))
|
||||
repoCall1 := tv.boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.stateErr)
|
||||
err := tv.svc.ChangeState(context.Background(), tc.session, tc.token, tc.id, tc.state)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
@@ -1261,7 +1261,7 @@ func TestRemoveConfigHandler(t *testing.T) {
|
||||
|
||||
lastID := "0"
|
||||
for _, tc := range cases {
|
||||
repoCall := tv.boot.On("RemoveThing", context.Background(), mock.Anything).Return(tc.err)
|
||||
repoCall := tv.boot.On("RemoveClient", context.Background(), mock.Anything).Return(tc.err)
|
||||
err := tv.svc.RemoveConfigHandler(context.Background(), tc.configID)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
|
||||
@@ -1284,7 +1284,7 @@ func TestRemoveConfigHandler(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectThingHandler(t *testing.T) {
|
||||
func TestConnectClientHandler(t *testing.T) {
|
||||
err := redisClient.FlushAll(context.Background()).Err()
|
||||
assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
|
||||
|
||||
@@ -1293,41 +1293,41 @@ func TestConnectThingHandler(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
channelID string
|
||||
thingID string
|
||||
clientID string
|
||||
err error
|
||||
event map[string]interface{}
|
||||
}{
|
||||
{
|
||||
desc: "connect thing handler successfully",
|
||||
desc: "connect client handler successfully",
|
||||
channelID: channel.ID,
|
||||
thingID: "1",
|
||||
clientID: "1",
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"channel_id": channel.ID,
|
||||
"thing_id": "1",
|
||||
"operation": thingConnect,
|
||||
"client_id": "1",
|
||||
"operation": clientConnect,
|
||||
"timestamp": time.Now().UnixNano(),
|
||||
"occurred_at": time.Now().UnixNano(),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "connect non-existing thing handler",
|
||||
desc: "connect non-existing client handler",
|
||||
channelID: channel.ID,
|
||||
thingID: "unknown",
|
||||
clientID: "unknown",
|
||||
err: nil,
|
||||
event: nil,
|
||||
},
|
||||
{
|
||||
desc: "connect thing handler with empty thing ID",
|
||||
desc: "connect client handler with empty client ID",
|
||||
channelID: channel.ID,
|
||||
thingID: "",
|
||||
clientID: "",
|
||||
err: nil,
|
||||
event: nil,
|
||||
},
|
||||
{
|
||||
desc: "connect thing handler with empty channel ID",
|
||||
desc: "connect client handler with empty channel ID",
|
||||
channelID: "",
|
||||
thingID: "1",
|
||||
clientID: "1",
|
||||
err: nil,
|
||||
event: nil,
|
||||
},
|
||||
@@ -1335,8 +1335,8 @@ func TestConnectThingHandler(t *testing.T) {
|
||||
|
||||
lastID := "0"
|
||||
for _, tc := range cases {
|
||||
repoCall := tv.boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err)
|
||||
err := tv.svc.ConnectThingHandler(context.Background(), tc.channelID, tc.thingID)
|
||||
repoCall := tv.boot.On("ConnectClient", context.Background(), mock.Anything, mock.Anything).Return(tc.err)
|
||||
err := tv.svc.ConnectClientHandler(context.Background(), tc.channelID, tc.clientID)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
|
||||
streams := redisClient.XRead(context.Background(), &redis.XReadArgs{
|
||||
@@ -1358,7 +1358,7 @@ func TestConnectThingHandler(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectThingHandler(t *testing.T) {
|
||||
func TestDisconnectClientHandler(t *testing.T) {
|
||||
err := redisClient.FlushAll(context.Background()).Err()
|
||||
assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err))
|
||||
|
||||
@@ -1367,50 +1367,50 @@ func TestDisconnectThingHandler(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
channelID string
|
||||
thingID string
|
||||
clientID string
|
||||
err error
|
||||
event map[string]interface{}
|
||||
}{
|
||||
{
|
||||
desc: "disconnect thing handler successfully",
|
||||
desc: "disconnect client handler successfully",
|
||||
channelID: channel.ID,
|
||||
thingID: "1",
|
||||
clientID: "1",
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"channel_id": channel.ID,
|
||||
"thing_id": "1",
|
||||
"operation": thingDisconnect,
|
||||
"client_id": "1",
|
||||
"operation": clientDisconnect,
|
||||
"timestamp": time.Now().UnixNano(),
|
||||
"occurred_at": time.Now().UnixNano(),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "remove non-existing thing handler",
|
||||
desc: "remove non-existing client handler",
|
||||
channelID: "unknown",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "remove thing handler with empty thing ID",
|
||||
desc: "remove client handler with empty client ID",
|
||||
channelID: channel.ID,
|
||||
thingID: "",
|
||||
clientID: "",
|
||||
err: nil,
|
||||
event: nil,
|
||||
},
|
||||
{
|
||||
desc: "remove thing handler with empty channel ID",
|
||||
desc: "remove client handler with empty channel ID",
|
||||
channelID: "",
|
||||
err: nil,
|
||||
event: nil,
|
||||
},
|
||||
{
|
||||
desc: "remove thing handler successfully",
|
||||
desc: "remove client handler successfully",
|
||||
channelID: channel.ID,
|
||||
thingID: "1",
|
||||
clientID: "1",
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"channel_id": channel.ID,
|
||||
"thing_id": "1",
|
||||
"operation": thingDisconnect,
|
||||
"client_id": "1",
|
||||
"operation": clientDisconnect,
|
||||
"timestamp": time.Now().UnixNano(),
|
||||
"occurred_at": time.Now().UnixNano(),
|
||||
},
|
||||
@@ -1419,8 +1419,8 @@ func TestDisconnectThingHandler(t *testing.T) {
|
||||
|
||||
lastID := "0"
|
||||
for _, tc := range cases {
|
||||
repoCall := tv.boot.On("DisconnectThing", context.Background(), tc.channelID, tc.thingID).Return(tc.err)
|
||||
err := tv.svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID)
|
||||
repoCall := tv.boot.On("DisconnectClient", context.Background(), tc.channelID, tc.clientID).Return(tc.err)
|
||||
err := tv.svc.DisconnectClientHandler(context.Background(), tc.channelID, tc.clientID)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
|
||||
streams := redisClient.XRead(context.Background(), &redis.XReadArgs{
|
||||
|
||||
@@ -37,7 +37,7 @@ func (am *authorizationMiddleware) Add(ctx context.Context, session mgauthn.Sess
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) View(ctx context.Context, session mgauthn.Session, id string) (bootstrap.Config, error) {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.ViewPermission, policies.ThingType, id); err != nil {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.ViewPermission, policies.ClientType, id); err != nil {
|
||||
return bootstrap.Config{}, err
|
||||
}
|
||||
|
||||
@@ -45,23 +45,23 @@ func (am *authorizationMiddleware) View(ctx context.Context, session mgauthn.Ses
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) Update(ctx context.Context, session mgauthn.Session, cfg bootstrap.Config) error {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ThingType, cfg.ThingID); err != nil {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ClientType, cfg.ClientID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return am.svc.Update(ctx, session, cfg)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ThingType, thingID); err != nil {
|
||||
func (am *authorizationMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, clientID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ClientType, clientID); err != nil {
|
||||
return bootstrap.Config{}, err
|
||||
}
|
||||
|
||||
return am.svc.UpdateCert(ctx, session, thingID, clientCert, clientKey, caCert)
|
||||
return am.svc.UpdateCert(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) UpdateConnections(ctx context.Context, session mgauthn.Session, token, id string, connections []string) error {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ThingType, id); err != nil {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ClientType, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func (am *authorizationMiddleware) List(ctx context.Context, session mgauthn.Ses
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) Remove(ctx context.Context, session mgauthn.Session, id string) error {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.DeletePermission, policies.ThingType, id); err != nil {
|
||||
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.DeletePermission, policies.ClientType, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -107,12 +107,12 @@ func (am *authorizationMiddleware) RemoveChannelHandler(ctx context.Context, id
|
||||
return am.svc.RemoveChannelHandler(ctx, id)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) ConnectThingHandler(ctx context.Context, channelID, ThingID string) error {
|
||||
return am.svc.ConnectThingHandler(ctx, channelID, ThingID)
|
||||
func (am *authorizationMiddleware) ConnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
return am.svc.ConnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) DisconnectThingHandler(ctx context.Context, channelID, ThingID string) error {
|
||||
return am.svc.DisconnectThingHandler(ctx, channelID, ThingID)
|
||||
func (am *authorizationMiddleware) DisconnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
return am.svc.DisconnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, adminID string) error {
|
||||
|
||||
@@ -26,13 +26,13 @@ func LoggingMiddleware(svc bootstrap.Service, logger *slog.Logger) bootstrap.Ser
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
// Add logs the add request. It logs the thing ID and the time it took to complete the request.
|
||||
// Add logs the add request. It logs the client ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) Add(ctx context.Context, session mgauthn.Session, token string, cfg bootstrap.Config) (saved bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", saved.ThingID),
|
||||
slog.String("client_id", saved.ClientID),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
@@ -45,33 +45,33 @@ func (lm *loggingMiddleware) Add(ctx context.Context, session mgauthn.Session, t
|
||||
return lm.svc.Add(ctx, session, token, cfg)
|
||||
}
|
||||
|
||||
// View logs the view request. It logs the thing ID and the time it took to complete the request.
|
||||
// View logs the view request. It logs the client ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) View(ctx context.Context, session mgauthn.Session, id string) (saved bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", id),
|
||||
slog.String("client_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("View thing config failed", args...)
|
||||
lm.logger.Warn("View client config failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("View thing config completed successfully", args...)
|
||||
lm.logger.Info("View client config completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.View(ctx, session, id)
|
||||
}
|
||||
|
||||
// Update logs the update request. It logs bootstrap thing ID and the time it took to complete the request.
|
||||
// Update logs the update request. It logs bootstrap client ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) Update(ctx context.Context, session mgauthn.Session, cfg bootstrap.Config) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("config",
|
||||
slog.String("thing_id", cfg.ThingID),
|
||||
slog.String("client_id", cfg.ClientID),
|
||||
slog.String("name", cfg.Name),
|
||||
),
|
||||
}
|
||||
@@ -86,13 +86,13 @@ func (lm *loggingMiddleware) Update(ctx context.Context, session mgauthn.Session
|
||||
return lm.svc.Update(ctx, session, cfg)
|
||||
}
|
||||
|
||||
// UpdateCert logs the update_cert request. It logs thing ID and the time it took to complete the request.
|
||||
// UpdateCert logs the update_cert request. It logs client ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, thingID, clientCert, clientKey, caCert string) (cfg bootstrap.Config, err error) {
|
||||
func (lm *loggingMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, clientID, clientCert, clientKey, caCert string) (cfg bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", cfg.ThingID),
|
||||
slog.String("client_id", cfg.ClientID),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
@@ -102,7 +102,7 @@ func (lm *loggingMiddleware) UpdateCert(ctx context.Context, session mgauthn.Ses
|
||||
lm.logger.Info("Update bootstrap config certificate completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.UpdateCert(ctx, session, thingID, clientCert, clientKey, caCert)
|
||||
return lm.svc.UpdateCert(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
}
|
||||
|
||||
// UpdateConnections logs the update_connections request. It logs bootstrap ID and the time it took to complete the request.
|
||||
@@ -111,7 +111,7 @@ func (lm *loggingMiddleware) UpdateConnections(ctx context.Context, session mgau
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", id),
|
||||
slog.String("client_id", id),
|
||||
slog.Any("connections", connections),
|
||||
}
|
||||
if err != nil {
|
||||
@@ -155,7 +155,7 @@ func (lm *loggingMiddleware) Remove(ctx context.Context, session mgauthn.Session
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", id),
|
||||
slog.String("client_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
@@ -194,10 +194,10 @@ func (lm *loggingMiddleware) ChangeState(ctx context.Context, session mgauthn.Se
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Change thing state failed", args...)
|
||||
lm.logger.Warn("Change client state failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Change thing state completed successfully", args...)
|
||||
lm.logger.Info("Change client state completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.ChangeState(ctx, session, token, id, state)
|
||||
@@ -258,38 +258,38 @@ func (lm *loggingMiddleware) RemoveChannelHandler(ctx context.Context, id string
|
||||
return lm.svc.RemoveChannelHandler(ctx, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ConnectThingHandler(ctx context.Context, channelID, thingID string) (err error) {
|
||||
func (lm *loggingMiddleware) ConnectClientHandler(ctx context.Context, channelID, clientID string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("channel_id", channelID),
|
||||
slog.String("thing_id", thingID),
|
||||
slog.String("client_id", clientID),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Connect thing handler failed", args...)
|
||||
lm.logger.Warn("Connect client handler failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Connect thing handler completed successfully", args...)
|
||||
lm.logger.Info("Connect client handler completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.ConnectThingHandler(ctx, channelID, thingID)
|
||||
return lm.svc.ConnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) DisconnectThingHandler(ctx context.Context, channelID, thingID string) (err error) {
|
||||
func (lm *loggingMiddleware) DisconnectClientHandler(ctx context.Context, channelID, clientID string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("channel_id", channelID),
|
||||
slog.String("thing_id", thingID),
|
||||
slog.String("client_id", clientID),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
lm.logger.Warn("Disconnect thing handler failed", args...)
|
||||
lm.logger.Warn("Disconnect client handler failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Disconnect thing handler completed successfully", args...)
|
||||
lm.logger.Info("Disconnect client handler completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.DisconnectThingHandler(ctx, channelID, thingID)
|
||||
return lm.svc.DisconnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
@@ -62,13 +62,13 @@ func (mm *metricsMiddleware) Update(ctx context.Context, session mgauthn.Session
|
||||
}
|
||||
|
||||
// UpdateCert instruments UpdateCert method with metrics.
|
||||
func (mm *metricsMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, thingKey, clientCert, clientKey, caCert string) (cfg bootstrap.Config, err error) {
|
||||
func (mm *metricsMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, clientID, clientCert, clientKey, caCert string) (cfg bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
mm.counter.With("method", "update_cert").Add(1)
|
||||
mm.latency.With("method", "update_cert").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return mm.svc.UpdateCert(ctx, session, thingKey, clientCert, clientKey, caCert)
|
||||
return mm.svc.UpdateCert(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
}
|
||||
|
||||
// UpdateConnections instruments UpdateConnections method with metrics.
|
||||
@@ -151,22 +151,22 @@ func (mm *metricsMiddleware) RemoveChannelHandler(ctx context.Context, id string
|
||||
return mm.svc.RemoveChannelHandler(ctx, id)
|
||||
}
|
||||
|
||||
// ConnectThingHandler instruments ConnectThingHandler method with metrics.
|
||||
func (mm *metricsMiddleware) ConnectThingHandler(ctx context.Context, channelID, thingID string) (err error) {
|
||||
// ConnectClientHandler instruments ConnectClientHandler method with metrics.
|
||||
func (mm *metricsMiddleware) ConnectClientHandler(ctx context.Context, channelID, clientID string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
mm.counter.With("method", "connect_thing_handler").Add(1)
|
||||
mm.latency.With("method", "connect_thing_handler").Observe(time.Since(begin).Seconds())
|
||||
mm.counter.With("method", "connect_client_handler").Add(1)
|
||||
mm.latency.With("method", "connect_client_handler").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return mm.svc.ConnectThingHandler(ctx, channelID, thingID)
|
||||
return mm.svc.ConnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
// DisconnectThingHandler instruments DisconnectThingHandler method with metrics.
|
||||
func (mm *metricsMiddleware) DisconnectThingHandler(ctx context.Context, channelID, thingID string) (err error) {
|
||||
// DisconnectClientHandler instruments DisconnectClientHandler method with metrics.
|
||||
func (mm *metricsMiddleware) DisconnectClientHandler(ctx context.Context, channelID, clientID string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
mm.counter.With("method", "disconnect_thing_handler").Add(1)
|
||||
mm.latency.With("method", "disconnect_thing_handler").Observe(time.Since(begin).Seconds())
|
||||
mm.counter.With("method", "disconnect_client_handler").Add(1)
|
||||
mm.latency.With("method", "disconnect_client_handler").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return mm.svc.DisconnectThingHandler(ctx, channelID, thingID)
|
||||
return mm.svc.DisconnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
+23
-23
@@ -35,17 +35,17 @@ func (_m *ConfigRepository) ChangeState(ctx context.Context, domainID string, id
|
||||
return r0
|
||||
}
|
||||
|
||||
// ConnectThing provides a mock function with given fields: ctx, channelID, thingID
|
||||
func (_m *ConfigRepository) ConnectThing(ctx context.Context, channelID string, thingID string) error {
|
||||
ret := _m.Called(ctx, channelID, thingID)
|
||||
// ConnectClient provides a mock function with given fields: ctx, channelID, clientID
|
||||
func (_m *ConfigRepository) ConnectClient(ctx context.Context, channelID string, clientID string) error {
|
||||
ret := _m.Called(ctx, channelID, clientID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ConnectThing")
|
||||
panic("no return value specified for ConnectClient")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, channelID, thingID)
|
||||
r0 = rf(ctx, channelID, clientID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -53,17 +53,17 @@ func (_m *ConfigRepository) ConnectThing(ctx context.Context, channelID string,
|
||||
return r0
|
||||
}
|
||||
|
||||
// DisconnectThing provides a mock function with given fields: ctx, channelID, thingID
|
||||
func (_m *ConfigRepository) DisconnectThing(ctx context.Context, channelID string, thingID string) error {
|
||||
ret := _m.Called(ctx, channelID, thingID)
|
||||
// DisconnectClient provides a mock function with given fields: ctx, channelID, clientID
|
||||
func (_m *ConfigRepository) DisconnectClient(ctx context.Context, channelID string, clientID string) error {
|
||||
ret := _m.Called(ctx, channelID, clientID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DisconnectThing")
|
||||
panic("no return value specified for DisconnectClient")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, channelID, thingID)
|
||||
r0 = rf(ctx, channelID, clientID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -137,12 +137,12 @@ func (_m *ConfigRepository) RemoveChannel(ctx context.Context, id string) error
|
||||
return r0
|
||||
}
|
||||
|
||||
// RemoveThing provides a mock function with given fields: ctx, id
|
||||
func (_m *ConfigRepository) RemoveThing(ctx context.Context, id string) error {
|
||||
// RemoveClient provides a mock function with given fields: ctx, id
|
||||
func (_m *ConfigRepository) RemoveClient(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RemoveThing")
|
||||
panic("no return value specified for RemoveClient")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
@@ -155,9 +155,9 @@ func (_m *ConfigRepository) RemoveThing(ctx context.Context, id string) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// RetrieveAll provides a mock function with given fields: ctx, domainID, thingIDs, filter, offset, limit
|
||||
func (_m *ConfigRepository) RetrieveAll(ctx context.Context, domainID string, thingIDs []string, filter bootstrap.Filter, offset uint64, limit uint64) bootstrap.ConfigsPage {
|
||||
ret := _m.Called(ctx, domainID, thingIDs, filter, offset, limit)
|
||||
// RetrieveAll provides a mock function with given fields: ctx, domainID, clientIDs, filter, offset, limit
|
||||
func (_m *ConfigRepository) RetrieveAll(ctx context.Context, domainID string, clientIDs []string, filter bootstrap.Filter, offset uint64, limit uint64) bootstrap.ConfigsPage {
|
||||
ret := _m.Called(ctx, domainID, clientIDs, filter, offset, limit)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveAll")
|
||||
@@ -165,7 +165,7 @@ func (_m *ConfigRepository) RetrieveAll(ctx context.Context, domainID string, th
|
||||
|
||||
var r0 bootstrap.ConfigsPage
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, []string, bootstrap.Filter, uint64, uint64) bootstrap.ConfigsPage); ok {
|
||||
r0 = rf(ctx, domainID, thingIDs, filter, offset, limit)
|
||||
r0 = rf(ctx, domainID, clientIDs, filter, offset, limit)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bootstrap.ConfigsPage)
|
||||
}
|
||||
@@ -275,9 +275,9 @@ func (_m *ConfigRepository) Update(ctx context.Context, cfg bootstrap.Config) er
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateCert provides a mock function with given fields: ctx, domainID, thingID, clientCert, clientKey, caCert
|
||||
func (_m *ConfigRepository) UpdateCert(ctx context.Context, domainID string, thingID string, clientCert string, clientKey string, caCert string) (bootstrap.Config, error) {
|
||||
ret := _m.Called(ctx, domainID, thingID, clientCert, clientKey, caCert)
|
||||
// UpdateCert provides a mock function with given fields: ctx, domainID, clientID, clientCert, clientKey, caCert
|
||||
func (_m *ConfigRepository) UpdateCert(ctx context.Context, domainID string, clientID string, clientCert string, clientKey string, caCert string) (bootstrap.Config, error) {
|
||||
ret := _m.Called(ctx, domainID, clientID, clientCert, clientKey, caCert)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateCert")
|
||||
@@ -286,16 +286,16 @@ func (_m *ConfigRepository) UpdateCert(ctx context.Context, domainID string, thi
|
||||
var r0 bootstrap.Config
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string) (bootstrap.Config, error)); ok {
|
||||
return rf(ctx, domainID, thingID, clientCert, clientKey, caCert)
|
||||
return rf(ctx, domainID, clientID, clientCert, clientKey, caCert)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string) bootstrap.Config); ok {
|
||||
r0 = rf(ctx, domainID, thingID, clientCert, clientKey, caCert)
|
||||
r0 = rf(ctx, domainID, clientID, clientCert, clientKey, caCert)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bootstrap.Config)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, string) error); ok {
|
||||
r1 = rf(ctx, domainID, thingID, clientCert, clientKey, caCert)
|
||||
r1 = rf(ctx, domainID, clientID, clientCert, clientKey, caCert)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
+16
-16
@@ -92,17 +92,17 @@ func (_m *Service) ChangeState(ctx context.Context, session authn.Session, token
|
||||
return r0
|
||||
}
|
||||
|
||||
// ConnectThingHandler provides a mock function with given fields: ctx, channelID, ThingID
|
||||
func (_m *Service) ConnectThingHandler(ctx context.Context, channelID string, ThingID string) error {
|
||||
ret := _m.Called(ctx, channelID, ThingID)
|
||||
// ConnectClientHandler provides a mock function with given fields: ctx, channelID, clientID
|
||||
func (_m *Service) ConnectClientHandler(ctx context.Context, channelID string, clientID string) error {
|
||||
ret := _m.Called(ctx, channelID, clientID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ConnectThingHandler")
|
||||
panic("no return value specified for ConnectClientHandler")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, channelID, ThingID)
|
||||
r0 = rf(ctx, channelID, clientID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -110,17 +110,17 @@ func (_m *Service) ConnectThingHandler(ctx context.Context, channelID string, Th
|
||||
return r0
|
||||
}
|
||||
|
||||
// DisconnectThingHandler provides a mock function with given fields: ctx, channelID, ThingID
|
||||
func (_m *Service) DisconnectThingHandler(ctx context.Context, channelID string, ThingID string) error {
|
||||
ret := _m.Called(ctx, channelID, ThingID)
|
||||
// DisconnectClientHandler provides a mock function with given fields: ctx, channelID, clientID
|
||||
func (_m *Service) DisconnectClientHandler(ctx context.Context, channelID string, clientID string) error {
|
||||
ret := _m.Called(ctx, channelID, clientID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DisconnectThingHandler")
|
||||
panic("no return value specified for DisconnectClientHandler")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, channelID, ThingID)
|
||||
r0 = rf(ctx, channelID, clientID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -228,9 +228,9 @@ func (_m *Service) Update(ctx context.Context, session authn.Session, cfg bootst
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateCert provides a mock function with given fields: ctx, session, thingID, clientCert, clientKey, caCert
|
||||
func (_m *Service) UpdateCert(ctx context.Context, session authn.Session, thingID string, clientCert string, clientKey string, caCert string) (bootstrap.Config, error) {
|
||||
ret := _m.Called(ctx, session, thingID, clientCert, clientKey, caCert)
|
||||
// UpdateCert provides a mock function with given fields: ctx, session, clientID, clientCert, clientKey, caCert
|
||||
func (_m *Service) UpdateCert(ctx context.Context, session authn.Session, clientID string, clientCert string, clientKey string, caCert string) (bootstrap.Config, error) {
|
||||
ret := _m.Called(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateCert")
|
||||
@@ -239,16 +239,16 @@ func (_m *Service) UpdateCert(ctx context.Context, session authn.Session, thingI
|
||||
var r0 bootstrap.Config
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, string, string) (bootstrap.Config, error)); ok {
|
||||
return rf(ctx, session, thingID, clientCert, clientKey, caCert)
|
||||
return rf(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, string, string) bootstrap.Config); ok {
|
||||
r0 = rf(ctx, session, thingID, clientCert, clientKey, caCert)
|
||||
r0 = rf(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bootstrap.Config)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, string, string) error); ok {
|
||||
r1 = rf(ctx, session, thingID, clientCert, clientKey, caCert)
|
||||
r1 = rf(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/bootstrap"
|
||||
"github.com/absmach/magistrala/clients"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
|
||||
"github.com/absmach/magistrala/pkg/postgres"
|
||||
"github.com/absmach/magistrala/things"
|
||||
"github.com/jackc/pgerrcode"
|
||||
"github.com/jackc/pgtype"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
@@ -24,12 +24,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errSaveChannels = errors.New("failed to insert channels to database")
|
||||
errSaveConnections = errors.New("failed to insert connections to database")
|
||||
errUpdateChannels = errors.New("failed to update channels in bootstrap configuration database")
|
||||
errRemoveChannels = errors.New("failed to remove channels from bootstrap configuration in database")
|
||||
errConnectThing = errors.New("failed to connect thing in bootstrap configuration in database")
|
||||
errDisconnectThing = errors.New("failed to disconnect thing in bootstrap configuration in database")
|
||||
errSaveChannels = errors.New("failed to insert channels to database")
|
||||
errSaveConnections = errors.New("failed to insert connections to database")
|
||||
errUpdateChannels = errors.New("failed to update channels in bootstrap configuration database")
|
||||
errRemoveChannels = errors.New("failed to remove channels from bootstrap configuration in database")
|
||||
errConnectClient = errors.New("failed to connect client in bootstrap configuration in database")
|
||||
errDisconnectClient = errors.New("failed to disconnect client in bootstrap configuration in database")
|
||||
)
|
||||
|
||||
const cleanupQuery = `DELETE FROM channels ch WHERE NOT EXISTS (
|
||||
@@ -48,9 +48,9 @@ func NewConfigRepository(db postgres.Database, log *slog.Logger) bootstrap.Confi
|
||||
return &configRepository{db: db, log: log}
|
||||
}
|
||||
|
||||
func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsConnIDs []string) (thingID string, err error) {
|
||||
q := `INSERT INTO configs (magistrala_thing, domain_id, name, client_cert, client_key, ca_cert, magistrala_key, external_id, external_key, content, state)
|
||||
VALUES (:magistrala_thing, :domain_id, :name, :client_cert, :client_key, :ca_cert, :magistrala_key, :external_id, :external_key, :content, :state)`
|
||||
func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsConnIDs []string) (clientID string, err error) {
|
||||
q := `INSERT INTO configs (magistrala_client, domain_id, name, client_cert, client_key, ca_cert, magistrala_secret, external_id, external_key, content, state)
|
||||
VALUES (:magistrala_client, :domain_id, :name, :client_cert, :client_key, :ca_cert, :magistrala_secret, :external_id, :external_key, :content, :state)`
|
||||
|
||||
tx, err := cr.db.BeginTxx(ctx, nil)
|
||||
if err != nil {
|
||||
@@ -86,16 +86,16 @@ func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsCo
|
||||
return "", commitErr
|
||||
}
|
||||
|
||||
return cfg.ThingID, nil
|
||||
return cfg.ClientID, nil
|
||||
}
|
||||
|
||||
func (cr configRepository) RetrieveByID(ctx context.Context, domainID, id string) (bootstrap.Config, error) {
|
||||
q := `SELECT magistrala_thing, magistrala_key, external_id, external_key, name, content, state, client_cert, ca_cert
|
||||
q := `SELECT magistrala_client, magistrala_secret, external_id, external_key, name, content, state, client_cert, ca_cert
|
||||
FROM configs
|
||||
WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id`
|
||||
WHERE magistrala_client = :magistrala_client AND domain_id = :domain_id`
|
||||
|
||||
dbcfg := dbConfig{
|
||||
ThingID: id,
|
||||
ClientID: id,
|
||||
DomainID: domainID,
|
||||
}
|
||||
row, err := cr.db.NamedQueryContext(ctx, q, dbcfg)
|
||||
@@ -118,7 +118,7 @@ func (cr configRepository) RetrieveByID(ctx context.Context, domainID, id string
|
||||
q = `SELECT magistrala_channel, name, metadata FROM channels ch
|
||||
INNER JOIN connections conn
|
||||
ON ch.magistrala_channel = conn.channel_id AND ch.domain_id = conn.domain_id
|
||||
WHERE conn.config_id = :magistrala_thing AND conn.domain_id = :domain_id`
|
||||
WHERE conn.config_id = :magistrala_client AND conn.domain_id = :domain_id`
|
||||
|
||||
rows, err := cr.db.NamedQueryContext(ctx, q, dbcfg)
|
||||
if err != nil {
|
||||
@@ -131,7 +131,7 @@ func (cr configRepository) RetrieveByID(ctx context.Context, domainID, id string
|
||||
for rows.Next() {
|
||||
dbch := dbChannel{}
|
||||
if err := rows.StructScan(&dbch); err != nil {
|
||||
cr.log.Error(fmt.Sprintf("Failed to read connected thing due to %s", err))
|
||||
cr.log.Error(fmt.Sprintf("Failed to read connected client due to %s", err))
|
||||
return bootstrap.Config{}, errors.Wrap(repoerr.ErrViewEntity, err)
|
||||
}
|
||||
dbch.DomainID = nullString(dbcfg.DomainID)
|
||||
@@ -149,12 +149,12 @@ func (cr configRepository) RetrieveByID(ctx context.Context, domainID, id string
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (cr configRepository) RetrieveAll(ctx context.Context, domainID string, thingIDs []string, filter bootstrap.Filter, offset, limit uint64) bootstrap.ConfigsPage {
|
||||
search, params := buildRetrieveQueryParams(domainID, thingIDs, filter)
|
||||
func (cr configRepository) RetrieveAll(ctx context.Context, domainID string, clientIDs []string, filter bootstrap.Filter, offset, limit uint64) bootstrap.ConfigsPage {
|
||||
search, params := buildRetrieveQueryParams(domainID, clientIDs, filter)
|
||||
n := len(params)
|
||||
|
||||
q := `SELECT magistrala_thing, magistrala_key, external_id, external_key, name, content, state
|
||||
FROM configs %s ORDER BY magistrala_thing LIMIT $%d OFFSET $%d`
|
||||
q := `SELECT magistrala_client, magistrala_secret, external_id, external_key, name, content, state
|
||||
FROM configs %s ORDER BY magistrala_client LIMIT $%d OFFSET $%d`
|
||||
q = fmt.Sprintf(q, search, n+1, n+2)
|
||||
|
||||
rows, err := cr.db.QueryContext(ctx, q, append(params, limit, offset)...)
|
||||
@@ -169,7 +169,7 @@ func (cr configRepository) RetrieveAll(ctx context.Context, domainID string, thi
|
||||
|
||||
for rows.Next() {
|
||||
c := bootstrap.Config{DomainID: domainID}
|
||||
if err := rows.Scan(&c.ThingID, &c.ThingKey, &c.ExternalID, &c.ExternalKey, &name, &content, &c.State); err != nil {
|
||||
if err := rows.Scan(&c.ClientID, &c.ClientSecret, &c.ExternalID, &c.ExternalKey, &name, &content, &c.State); err != nil {
|
||||
cr.log.Error(fmt.Sprintf("Failed to read retrieved config due to %s", err))
|
||||
return bootstrap.ConfigsPage{}
|
||||
}
|
||||
@@ -196,7 +196,7 @@ func (cr configRepository) RetrieveAll(ctx context.Context, domainID string, thi
|
||||
}
|
||||
|
||||
func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID string) (bootstrap.Config, error) {
|
||||
q := `SELECT magistrala_thing, magistrala_key, external_key, domain_id, name, client_cert, client_key, ca_cert, content, state
|
||||
q := `SELECT magistrala_client, magistrala_secret, external_key, domain_id, name, client_cert, client_key, ca_cert, content, state
|
||||
FROM configs
|
||||
WHERE external_id = :external_id`
|
||||
dbcfg := dbConfig{
|
||||
@@ -222,7 +222,7 @@ func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID
|
||||
q = `SELECT magistrala_channel, name, metadata FROM channels ch
|
||||
INNER JOIN connections conn
|
||||
ON ch.magistrala_channel = conn.channel_id AND ch.domain_id = conn.domain_id
|
||||
WHERE conn.config_id = :magistrala_thing AND conn.domain_id = :domain_id`
|
||||
WHERE conn.config_id = :magistrala_client AND conn.domain_id = :domain_id`
|
||||
|
||||
rows, err := cr.db.NamedQueryContext(ctx, q, dbcfg)
|
||||
if err != nil {
|
||||
@@ -235,7 +235,7 @@ func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID
|
||||
for rows.Next() {
|
||||
dbch := dbChannel{}
|
||||
if err := rows.StructScan(&dbch); err != nil {
|
||||
cr.log.Error(fmt.Sprintf("Failed to read connected thing due to %s", err))
|
||||
cr.log.Error(fmt.Sprintf("Failed to read connected client due to %s", err))
|
||||
return bootstrap.Config{}, errors.Wrap(repoerr.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
@@ -255,12 +255,12 @@ func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID
|
||||
}
|
||||
|
||||
func (cr configRepository) Update(ctx context.Context, cfg bootstrap.Config) error {
|
||||
q := `UPDATE configs SET name = :name, content = :content WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id `
|
||||
q := `UPDATE configs SET name = :name, content = :content WHERE magistrala_client = :magistrala_client AND domain_id = :domain_id `
|
||||
|
||||
dbcfg := dbConfig{
|
||||
Name: nullString(cfg.Name),
|
||||
Content: nullString(cfg.Content),
|
||||
ThingID: cfg.ThingID,
|
||||
ClientID: cfg.ClientID,
|
||||
DomainID: cfg.DomainID,
|
||||
}
|
||||
|
||||
@@ -281,12 +281,12 @@ func (cr configRepository) Update(ctx context.Context, cfg bootstrap.Config) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr configRepository) UpdateCert(ctx context.Context, domainID, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
q := `UPDATE configs SET client_cert = :client_cert, client_key = :client_key, ca_cert = :ca_cert WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id
|
||||
RETURNING magistrala_thing, client_cert, client_key, ca_cert`
|
||||
func (cr configRepository) UpdateCert(ctx context.Context, domainID, clientID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
q := `UPDATE configs SET client_cert = :client_cert, client_key = :client_key, ca_cert = :ca_cert WHERE magistrala_client = :magistrala_client AND domain_id = :domain_id
|
||||
RETURNING magistrala_client, client_cert, client_key, ca_cert`
|
||||
|
||||
dbcfg := dbConfig{
|
||||
ThingID: thingID,
|
||||
ClientID: clientID,
|
||||
ClientCert: nullString(clientCert),
|
||||
DomainID: domainID,
|
||||
ClientKey: nullString(clientKey),
|
||||
@@ -345,9 +345,9 @@ func (cr configRepository) UpdateConnections(ctx context.Context, domainID, id s
|
||||
}
|
||||
|
||||
func (cr configRepository) Remove(ctx context.Context, domainID, id string) error {
|
||||
q := `DELETE FROM configs WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id`
|
||||
q := `DELETE FROM configs WHERE magistrala_client = :magistrala_client AND domain_id = :domain_id`
|
||||
dbcfg := dbConfig{
|
||||
ThingID: id,
|
||||
ClientID: id,
|
||||
DomainID: domainID,
|
||||
}
|
||||
|
||||
@@ -363,10 +363,10 @@ func (cr configRepository) Remove(ctx context.Context, domainID, id string) erro
|
||||
}
|
||||
|
||||
func (cr configRepository) ChangeState(ctx context.Context, domainID, id string, state bootstrap.State) error {
|
||||
q := `UPDATE configs SET state = :state WHERE magistrala_thing = :magistrala_thing AND domain_id = :domain_id;`
|
||||
q := `UPDATE configs SET state = :state WHERE magistrala_client = :magistrala_client AND domain_id = :domain_id;`
|
||||
|
||||
dbcfg := dbConfig{
|
||||
ThingID: id,
|
||||
ClientID: id,
|
||||
State: state,
|
||||
DomainID: domainID,
|
||||
}
|
||||
@@ -424,8 +424,8 @@ func (cr configRepository) ListExisting(ctx context.Context, domainID string, id
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
func (cr configRepository) RemoveThing(ctx context.Context, id string) error {
|
||||
q := `DELETE FROM configs WHERE magistrala_thing = $1`
|
||||
func (cr configRepository) RemoveClient(ctx context.Context, id string) error {
|
||||
q := `DELETE FROM configs WHERE magistrala_client = $1`
|
||||
_, err := cr.db.ExecContext(ctx, q, id)
|
||||
|
||||
if _, err := cr.db.ExecContext(ctx, cleanupQuery); err != nil {
|
||||
@@ -459,14 +459,14 @@ func (cr configRepository) RemoveChannel(ctx context.Context, id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr configRepository) ConnectThing(ctx context.Context, channelID, thingID string) error {
|
||||
func (cr configRepository) ConnectClient(ctx context.Context, channelID, clientID string) error {
|
||||
q := `UPDATE configs SET state = $1
|
||||
WHERE magistrala_thing = $2
|
||||
WHERE magistrala_client = $2
|
||||
AND EXISTS (SELECT 1 FROM connections WHERE config_id = $2 AND channel_id = $3)`
|
||||
|
||||
result, err := cr.db.ExecContext(ctx, q, bootstrap.Active, thingID, channelID)
|
||||
result, err := cr.db.ExecContext(ctx, q, bootstrap.Active, clientID, channelID)
|
||||
if err != nil {
|
||||
return errors.Wrap(errConnectThing, err)
|
||||
return errors.Wrap(errConnectClient, err)
|
||||
}
|
||||
if rows, _ := result.RowsAffected(); rows == 0 {
|
||||
return repoerr.ErrNotFound
|
||||
@@ -474,23 +474,23 @@ func (cr configRepository) ConnectThing(ctx context.Context, channelID, thingID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr configRepository) DisconnectThing(ctx context.Context, channelID, thingID string) error {
|
||||
func (cr configRepository) DisconnectClient(ctx context.Context, channelID, clientID string) error {
|
||||
q := `UPDATE configs SET state = $1
|
||||
WHERE magistrala_thing = $2
|
||||
WHERE magistrala_client = $2
|
||||
AND EXISTS (SELECT 1 FROM connections WHERE config_id = $2 AND channel_id = $3)`
|
||||
_, err := cr.db.ExecContext(ctx, q, bootstrap.Inactive, thingID, channelID)
|
||||
_, err := cr.db.ExecContext(ctx, q, bootstrap.Inactive, clientID, channelID)
|
||||
if err != nil {
|
||||
return errors.Wrap(errDisconnectThing, err)
|
||||
return errors.Wrap(errDisconnectClient, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildRetrieveQueryParams(domainID string, thingIDs []string, filter bootstrap.Filter) (string, []interface{}) {
|
||||
func buildRetrieveQueryParams(domainID string, clientIDs []string, filter bootstrap.Filter) (string, []interface{}) {
|
||||
params := []interface{}{}
|
||||
queries := []string{}
|
||||
|
||||
if len(thingIDs) != 0 {
|
||||
queries = append(queries, fmt.Sprintf("magistrala_thing IN ('%s')", strings.Join(thingIDs, "','")))
|
||||
if len(clientIDs) != 0 {
|
||||
queries = append(queries, fmt.Sprintf("magistrala_client IN ('%s')", strings.Join(clientIDs, "','")))
|
||||
} else if domainID != "" {
|
||||
params = append(params, domainID)
|
||||
queries = append(queries, fmt.Sprintf("domain_id = $%d", len(params)))
|
||||
@@ -560,7 +560,7 @@ func insertConnections(_ context.Context, cfg bootstrap.Config, connections []st
|
||||
conns := []dbConnection{}
|
||||
for _, conn := range connections {
|
||||
dbconn := dbConnection{
|
||||
Config: cfg.ThingID,
|
||||
Config: cfg.ClientID,
|
||||
Channel: conn,
|
||||
DomainID: cfg.DomainID,
|
||||
}
|
||||
@@ -644,43 +644,43 @@ func nullTime(t time.Time) sql.NullTime {
|
||||
}
|
||||
|
||||
type dbConfig struct {
|
||||
ThingID string `db:"magistrala_thing"`
|
||||
DomainID string `db:"domain_id"`
|
||||
Name sql.NullString `db:"name"`
|
||||
ClientCert sql.NullString `db:"client_cert"`
|
||||
ClientKey sql.NullString `db:"client_key"`
|
||||
CaCert sql.NullString `db:"ca_cert"`
|
||||
ThingKey string `db:"magistrala_key"`
|
||||
ExternalID string `db:"external_id"`
|
||||
ExternalKey string `db:"external_key"`
|
||||
Content sql.NullString `db:"content"`
|
||||
State bootstrap.State `db:"state"`
|
||||
DomainID string `db:"domain_id"`
|
||||
ClientID string `db:"magistrala_client"`
|
||||
ClientSecret string `db:"magistrala_secret"`
|
||||
Name sql.NullString `db:"name"`
|
||||
ClientCert sql.NullString `db:"client_cert"`
|
||||
ClientKey sql.NullString `db:"client_key"`
|
||||
CaCert sql.NullString `db:"ca_cert"`
|
||||
ExternalID string `db:"external_id"`
|
||||
ExternalKey string `db:"external_key"`
|
||||
Content sql.NullString `db:"content"`
|
||||
State bootstrap.State `db:"state"`
|
||||
}
|
||||
|
||||
func toDBConfig(cfg bootstrap.Config) dbConfig {
|
||||
return dbConfig{
|
||||
ThingID: cfg.ThingID,
|
||||
DomainID: cfg.DomainID,
|
||||
Name: nullString(cfg.Name),
|
||||
ClientCert: nullString(cfg.ClientCert),
|
||||
ClientKey: nullString(cfg.ClientKey),
|
||||
CaCert: nullString(cfg.CACert),
|
||||
ThingKey: cfg.ThingKey,
|
||||
ExternalID: cfg.ExternalID,
|
||||
ExternalKey: cfg.ExternalKey,
|
||||
Content: nullString(cfg.Content),
|
||||
State: cfg.State,
|
||||
ClientID: cfg.ClientID,
|
||||
ClientSecret: cfg.ClientSecret,
|
||||
DomainID: cfg.DomainID,
|
||||
Name: nullString(cfg.Name),
|
||||
ClientCert: nullString(cfg.ClientCert),
|
||||
ClientKey: nullString(cfg.ClientKey),
|
||||
CaCert: nullString(cfg.CACert),
|
||||
ExternalID: cfg.ExternalID,
|
||||
ExternalKey: cfg.ExternalKey,
|
||||
Content: nullString(cfg.Content),
|
||||
State: cfg.State,
|
||||
}
|
||||
}
|
||||
|
||||
func toConfig(dbcfg dbConfig) bootstrap.Config {
|
||||
cfg := bootstrap.Config{
|
||||
ThingID: dbcfg.ThingID,
|
||||
DomainID: dbcfg.DomainID,
|
||||
ThingKey: dbcfg.ThingKey,
|
||||
ExternalID: dbcfg.ExternalID,
|
||||
ExternalKey: dbcfg.ExternalKey,
|
||||
State: dbcfg.State,
|
||||
ClientID: dbcfg.ClientID,
|
||||
ClientSecret: dbcfg.ClientSecret,
|
||||
DomainID: dbcfg.DomainID,
|
||||
ExternalID: dbcfg.ExternalID,
|
||||
ExternalKey: dbcfg.ExternalKey,
|
||||
State: dbcfg.State,
|
||||
}
|
||||
|
||||
if dbcfg.Name.Valid {
|
||||
@@ -715,7 +715,7 @@ type dbChannel struct {
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
|
||||
UpdatedBy sql.NullString `db:"updated_by,omitempty"`
|
||||
Status things.Status `db:"status"`
|
||||
Status clients.Status `db:"status"`
|
||||
}
|
||||
|
||||
func toDBChannel(domainID string, ch bootstrap.Channel) (dbChannel, error) {
|
||||
|
||||
+109
-109
@@ -23,11 +23,11 @@ const numConfigs = 10
|
||||
|
||||
var (
|
||||
config = bootstrap.Config{
|
||||
ThingID: "mg-thing",
|
||||
ThingKey: "mg-key",
|
||||
ExternalID: "external-id",
|
||||
ExternalKey: "external-key",
|
||||
DomainID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ClientID: "mg-client",
|
||||
ClientSecret: "mg-key",
|
||||
ExternalID: "external-id",
|
||||
ExternalKey: "external-key",
|
||||
DomainID: testsutil.GenerateUUID(&testing.T{}),
|
||||
Channels: []bootstrap.Channel{
|
||||
{ID: "1", Name: "name 1", Metadata: map[string]interface{}{"meta": 1.0}},
|
||||
{ID: "2", Name: "name 2", Metadata: map[string]interface{}{"meta": 2.0}},
|
||||
@@ -46,20 +46,20 @@ func TestSave(t *testing.T) {
|
||||
|
||||
diff := "different"
|
||||
|
||||
duplicateThing := config
|
||||
duplicateThing.ExternalID = diff
|
||||
duplicateThing.ThingKey = diff
|
||||
duplicateThing.Channels = []bootstrap.Channel{}
|
||||
duplicateClient := config
|
||||
duplicateClient.ExternalID = diff
|
||||
duplicateClient.ClientSecret = diff
|
||||
duplicateClient.Channels = []bootstrap.Channel{}
|
||||
|
||||
duplicateExternal := config
|
||||
duplicateExternal.ThingID = diff
|
||||
duplicateExternal.ThingKey = diff
|
||||
duplicateExternal.ClientID = diff
|
||||
duplicateExternal.ClientSecret = diff
|
||||
duplicateExternal.Channels = []bootstrap.Channel{}
|
||||
|
||||
duplicateChannels := config
|
||||
duplicateChannels.ExternalID = diff
|
||||
duplicateChannels.ThingKey = diff
|
||||
duplicateChannels.ThingID = diff
|
||||
duplicateChannels.ClientSecret = diff
|
||||
duplicateChannels.ClientID = diff
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -74,8 +74,8 @@ func TestSave(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "save config with same Thing ID",
|
||||
config: duplicateThing,
|
||||
desc: "save config with same Client ID",
|
||||
config: duplicateClient,
|
||||
connections: nil,
|
||||
err: repoerr.ErrConflict,
|
||||
},
|
||||
@@ -96,7 +96,7 @@ func TestSave(t *testing.T) {
|
||||
id, err := repo.Save(context.Background(), tc.config, tc.connections)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
if err == nil {
|
||||
assert.Equal(t, id, tc.config.ThingID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.config.ThingID, id))
|
||||
assert.Equal(t, id, tc.config.ClientID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.config.ClientID, id))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,8 +110,8 @@ func TestRetrieveByID(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
require.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
id, err := repo.Save(context.Background(), c, channels)
|
||||
@@ -162,7 +162,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
err := deleteChannels(context.Background(), repo)
|
||||
require.Nil(t, err, "Channels cleanup expected to succeed.")
|
||||
|
||||
thingIDs := make([]string, numConfigs)
|
||||
clientIDs := make([]string, numConfigs)
|
||||
|
||||
for i := 0; i < numConfigs; i++ {
|
||||
c := config
|
||||
@@ -172,10 +172,10 @@ func TestRetrieveAll(t *testing.T) {
|
||||
require.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ExternalID = uid.String()
|
||||
c.Name = fmt.Sprintf("name %d", i)
|
||||
c.ThingID = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
|
||||
thingIDs[i] = c.ThingID
|
||||
clientIDs[i] = c.ClientID
|
||||
|
||||
if i%2 == 0 {
|
||||
c.State = bootstrap.Active
|
||||
@@ -191,7 +191,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
domainID string
|
||||
thingID []string
|
||||
clientID []string
|
||||
offset uint64
|
||||
limit uint64
|
||||
filter bootstrap.Filter
|
||||
@@ -200,7 +200,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
{
|
||||
desc: "retrieve all configs",
|
||||
domainID: config.DomainID,
|
||||
thingID: []string{},
|
||||
clientID: []string{},
|
||||
offset: 0,
|
||||
limit: uint64(numConfigs),
|
||||
size: numConfigs,
|
||||
@@ -208,7 +208,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
{
|
||||
desc: "retrieve a subset of configs",
|
||||
domainID: config.DomainID,
|
||||
thingID: []string{},
|
||||
clientID: []string{},
|
||||
offset: 5,
|
||||
limit: uint64(numConfigs - 5),
|
||||
size: numConfigs - 5,
|
||||
@@ -216,7 +216,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
{
|
||||
desc: "retrieve with wrong domain ID ",
|
||||
domainID: "2",
|
||||
thingID: []string{},
|
||||
clientID: []string{},
|
||||
offset: 0,
|
||||
limit: uint64(numConfigs),
|
||||
size: 0,
|
||||
@@ -224,7 +224,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
{
|
||||
desc: "retrieve all active configs ",
|
||||
domainID: config.DomainID,
|
||||
thingID: []string{},
|
||||
clientID: []string{},
|
||||
offset: 0,
|
||||
limit: uint64(numConfigs),
|
||||
filter: bootstrap.Filter{FullMatch: map[string]string{"state": bootstrap.Active.String()}},
|
||||
@@ -233,7 +233,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
{
|
||||
desc: "retrieve all with partial match filter",
|
||||
domainID: config.DomainID,
|
||||
thingID: []string{},
|
||||
clientID: []string{},
|
||||
offset: 0,
|
||||
limit: uint64(numConfigs),
|
||||
filter: bootstrap.Filter{PartialMatch: map[string]string{"name": "1"}},
|
||||
@@ -242,31 +242,31 @@ func TestRetrieveAll(t *testing.T) {
|
||||
{
|
||||
desc: "retrieve search by name",
|
||||
domainID: config.DomainID,
|
||||
thingID: []string{},
|
||||
clientID: []string{},
|
||||
offset: 0,
|
||||
limit: uint64(numConfigs),
|
||||
filter: bootstrap.Filter{PartialMatch: map[string]string{"name": "1"}},
|
||||
size: 1,
|
||||
},
|
||||
{
|
||||
desc: "retrieve by valid thingIDs",
|
||||
desc: "retrieve by valid clientIDs",
|
||||
domainID: config.DomainID,
|
||||
thingID: thingIDs,
|
||||
clientID: clientIDs,
|
||||
offset: 0,
|
||||
limit: uint64(numConfigs),
|
||||
size: 10,
|
||||
},
|
||||
{
|
||||
desc: "retrieve by non-existing thingID",
|
||||
desc: "retrieve by non-existing clientID",
|
||||
domainID: config.DomainID,
|
||||
thingID: []string{"non-existing"},
|
||||
clientID: []string{"non-existing"},
|
||||
offset: 0,
|
||||
limit: uint64(numConfigs),
|
||||
size: 0,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
ret := repo.RetrieveAll(context.Background(), tc.domainID, tc.thingID, tc.filter, tc.offset, tc.limit)
|
||||
ret := repo.RetrieveAll(context.Background(), tc.domainID, tc.clientID, tc.filter, tc.offset, tc.limit)
|
||||
size := len(ret.Configs)
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", tc.desc, tc.size, size))
|
||||
}
|
||||
@@ -281,8 +281,8 @@ func TestRetrieveByExternalID(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -319,8 +319,8 @@ func TestUpdate(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -364,8 +364,8 @@ func TestUpdateCert(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -379,7 +379,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
clientID string
|
||||
domainID string
|
||||
cert string
|
||||
certKey string
|
||||
@@ -389,7 +389,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "update with wrong domain ID ",
|
||||
thingID: "",
|
||||
clientID: "",
|
||||
cert: "cert",
|
||||
certKey: "certKey",
|
||||
ca: "",
|
||||
@@ -399,13 +399,13 @@ func TestUpdateCert(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update a config",
|
||||
thingID: c.ThingID,
|
||||
clientID: c.ClientID,
|
||||
cert: "cert",
|
||||
certKey: "certKey",
|
||||
ca: "ca",
|
||||
domainID: c.DomainID,
|
||||
expectedConfig: bootstrap.Config{
|
||||
ThingID: c.ThingID,
|
||||
ClientID: c.ClientID,
|
||||
ClientCert: "cert",
|
||||
CACert: "ca",
|
||||
ClientKey: "certKey",
|
||||
@@ -415,7 +415,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
cfg, err := repo.UpdateCert(context.Background(), tc.domainID, tc.thingID, tc.cert, tc.certKey, tc.ca)
|
||||
cfg, err := repo.UpdateCert(context.Background(), tc.domainID, tc.clientID, tc.cert, tc.certKey, tc.ca)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.expectedConfig, cfg, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.expectedConfig, cfg))
|
||||
}
|
||||
@@ -430,8 +430,8 @@ func TestUpdateConnections(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -439,8 +439,8 @@ func TestUpdateConnections(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err = uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
c.Channels = []bootstrap.Channel{}
|
||||
@@ -466,7 +466,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections",
|
||||
domainID: config.DomainID,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
channels: nil,
|
||||
connections: []string{channels[1]},
|
||||
err: nil,
|
||||
@@ -482,7 +482,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections no channels",
|
||||
domainID: config.DomainID,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
channels: nil,
|
||||
connections: nil,
|
||||
err: nil,
|
||||
@@ -503,8 +503,8 @@ func TestRemove(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
id, err := repo.Save(context.Background(), c, channels)
|
||||
@@ -530,8 +530,8 @@ func TestChangeState(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
saved, err := repo.Save(context.Background(), c, channels)
|
||||
@@ -586,8 +586,8 @@ func TestListExisting(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -628,7 +628,7 @@ func TestListExisting(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveThing(t *testing.T) {
|
||||
func TestRemoveClient(t *testing.T) {
|
||||
repo := postgres.NewConfigRepository(db, testLog)
|
||||
err := deleteChannels(context.Background(), repo)
|
||||
require.Nil(t, err, "Channels cleanup expected to succeed.")
|
||||
@@ -637,14 +637,14 @@ func TestRemoveThing(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
saved, err := repo.Save(context.Background(), c, channels)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
for i := 0; i < 2; i++ {
|
||||
err := repo.RemoveThing(context.Background(), saved)
|
||||
err := repo.RemoveClient(context.Background(), saved)
|
||||
assert.Nil(t, err, fmt.Sprintf("an unexpected error occurred: %s\n", err))
|
||||
}
|
||||
}
|
||||
@@ -658,8 +658,8 @@ func TestUpdateChannel(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -674,7 +674,7 @@ func TestUpdateChannel(t *testing.T) {
|
||||
err = repo.UpdateChannel(context.Background(), update)
|
||||
assert.Nil(t, err, fmt.Sprintf("updating config expected to succeed: %s.\n", err))
|
||||
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ClientID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
var retreved bootstrap.Channel
|
||||
for _, c := range cfg.Channels {
|
||||
@@ -695,8 +695,8 @@ func TestRemoveChannel(t *testing.T) {
|
||||
c := config
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -705,12 +705,12 @@ func TestRemoveChannel(t *testing.T) {
|
||||
err = repo.RemoveChannel(context.Background(), c.Channels[0].ID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ClientID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
assert.NotContains(t, cfg.Channels, c.Channels[0], fmt.Sprintf("expected to remove channel %s from %s", c.Channels[0], cfg.Channels))
|
||||
}
|
||||
|
||||
func TestConnectThing(t *testing.T) {
|
||||
func TestConnectClient(t *testing.T) {
|
||||
repo := postgres.NewConfigRepository(db, testLog)
|
||||
err := deleteChannels(context.Background(), repo)
|
||||
require.Nil(t, err, "Channels cleanup expected to succeed.")
|
||||
@@ -719,8 +719,8 @@ func TestConnectThing(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
c.State = bootstrap.Inactive
|
||||
@@ -729,14 +729,14 @@ func TestConnectThing(t *testing.T) {
|
||||
|
||||
wrongID := testsutil.GenerateUUID(&testing.T{})
|
||||
|
||||
connectedThing := c
|
||||
connectedClient := c
|
||||
|
||||
randomThing := c
|
||||
randomThingID, _ := uuid.NewV4()
|
||||
randomThing.ThingID = randomThingID.String()
|
||||
randomClient := c
|
||||
randomClientID, _ := uuid.NewV4()
|
||||
randomClient.ClientID = randomClientID.String()
|
||||
|
||||
emptyThing := c
|
||||
emptyThing.ThingID = ""
|
||||
emptyClient := c
|
||||
emptyClient.ClientID = ""
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -748,7 +748,7 @@ func TestConnectThing(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "connect disconnected thing",
|
||||
desc: "connect disconnected client",
|
||||
domainID: c.DomainID,
|
||||
id: saved,
|
||||
state: bootstrap.Inactive,
|
||||
@@ -757,16 +757,16 @@ func TestConnectThing(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "connect already connected thing",
|
||||
desc: "connect already connected client",
|
||||
domainID: c.DomainID,
|
||||
id: connectedThing.ThingID,
|
||||
state: connectedThing.State,
|
||||
id: connectedClient.ClientID,
|
||||
state: connectedClient.State,
|
||||
channels: c.Channels,
|
||||
connections: channels,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "connect non-existent thing",
|
||||
desc: "connect non-existent client",
|
||||
domainID: c.DomainID,
|
||||
id: wrongID,
|
||||
channels: c.Channels,
|
||||
@@ -774,17 +774,17 @@ func TestConnectThing(t *testing.T) {
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "connect random thing",
|
||||
desc: "connect random client",
|
||||
domainID: c.DomainID,
|
||||
id: randomThing.ThingID,
|
||||
id: randomClient.ClientID,
|
||||
channels: c.Channels,
|
||||
connections: channels,
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "connect empty thing",
|
||||
desc: "connect empty client",
|
||||
domainID: c.DomainID,
|
||||
id: emptyThing.ThingID,
|
||||
id: emptyClient.ClientID,
|
||||
channels: c.Channels,
|
||||
connections: channels,
|
||||
err: repoerr.ErrNotFound,
|
||||
@@ -793,23 +793,23 @@ func TestConnectThing(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
for i, ch := range tc.channels {
|
||||
if i == 0 {
|
||||
err = repo.ConnectThing(context.Background(), ch.ID, tc.id)
|
||||
err = repo.ConnectClient(context.Background(), ch.ID, tc.id)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: Expected error: %s, got: %s.\n", tc.desc, tc.err, err))
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ClientID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
assert.Equal(t, cfg.State, bootstrap.Active, fmt.Sprintf("expected to be active when a connection is added from %s", cfg))
|
||||
} else {
|
||||
_ = repo.ConnectThing(context.Background(), ch.ID, tc.id)
|
||||
_ = repo.ConnectClient(context.Background(), ch.ID, tc.id)
|
||||
}
|
||||
}
|
||||
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ClientID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
assert.Equal(t, cfg.State, bootstrap.Active, fmt.Sprintf("expected to be active when a connection is added from %s", cfg))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectThing(t *testing.T) {
|
||||
func TestDisconnectClient(t *testing.T) {
|
||||
repo := postgres.NewConfigRepository(db, testLog)
|
||||
err := deleteChannels(context.Background(), repo)
|
||||
require.Nil(t, err, "Channels cleanup expected to succeed.")
|
||||
@@ -818,8 +818,8 @@ func TestDisconnectThing(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ClientSecret = uid.String()
|
||||
c.ClientID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
c.State = bootstrap.Inactive
|
||||
@@ -828,14 +828,14 @@ func TestDisconnectThing(t *testing.T) {
|
||||
|
||||
wrongID := testsutil.GenerateUUID(&testing.T{})
|
||||
|
||||
connectedThing := c
|
||||
connectedClient := c
|
||||
|
||||
randomThing := c
|
||||
randomThingID, _ := uuid.NewV4()
|
||||
randomThing.ThingID = randomThingID.String()
|
||||
randomClient := c
|
||||
randomClientID, _ := uuid.NewV4()
|
||||
randomClient.ClientID = randomClientID.String()
|
||||
|
||||
emptyThing := c
|
||||
emptyThing.ThingID = ""
|
||||
emptyClient := c
|
||||
emptyClient.ClientID = ""
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -847,16 +847,16 @@ func TestDisconnectThing(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "disconnect connected thing",
|
||||
desc: "disconnect connected client",
|
||||
domainID: c.DomainID,
|
||||
id: connectedThing.ThingID,
|
||||
state: connectedThing.State,
|
||||
id: connectedClient.ClientID,
|
||||
state: connectedClient.State,
|
||||
channels: c.Channels,
|
||||
connections: channels,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "disconnect already disconnected thing",
|
||||
desc: "disconnect already disconnected client",
|
||||
domainID: c.DomainID,
|
||||
id: saved,
|
||||
state: bootstrap.Inactive,
|
||||
@@ -865,7 +865,7 @@ func TestDisconnectThing(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "disconnect invalid thing",
|
||||
desc: "disconnect invalid client",
|
||||
domainID: c.DomainID,
|
||||
id: wrongID,
|
||||
channels: c.Channels,
|
||||
@@ -873,17 +873,17 @@ func TestDisconnectThing(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "disconnect random thing",
|
||||
desc: "disconnect random client",
|
||||
domainID: c.DomainID,
|
||||
id: randomThing.ThingID,
|
||||
id: randomClient.ClientID,
|
||||
channels: c.Channels,
|
||||
connections: channels,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "disconnect empty thing",
|
||||
desc: "disconnect empty client",
|
||||
domainID: c.DomainID,
|
||||
id: emptyThing.ThingID,
|
||||
id: emptyClient.ClientID,
|
||||
channels: c.Channels,
|
||||
connections: channels,
|
||||
err: nil,
|
||||
@@ -892,11 +892,11 @@ func TestDisconnectThing(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
for _, ch := range tc.channels {
|
||||
err = repo.DisconnectThing(context.Background(), ch.ID, tc.id)
|
||||
err = repo.DisconnectClient(context.Background(), ch.ID, tc.id)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: Expected error: %s, got: %s.\n", tc.desc, tc.err, err))
|
||||
}
|
||||
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ThingID)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.DomainID, c.ClientID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
assert.Equal(t, cfg.State, bootstrap.Inactive, fmt.Sprintf("expected to be inactive when a connection is removed from %s", cfg))
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ func Migration() *migrate.MemoryMigrationSource {
|
||||
Id: "configs_1",
|
||||
Up: []string{
|
||||
`CREATE TABLE IF NOT EXISTS configs (
|
||||
mainflux_thing TEXT UNIQUE NOT NULL,
|
||||
mainflux_client TEXT UNIQUE NOT NULL,
|
||||
owner VARCHAR(254),
|
||||
name TEXT,
|
||||
mainflux_key CHAR(36) UNIQUE NOT NULL,
|
||||
@@ -24,7 +24,7 @@ func Migration() *migrate.MemoryMigrationSource {
|
||||
client_key TEXT,
|
||||
ca_cert TEXT,
|
||||
state BIGINT NOT NULL,
|
||||
PRIMARY KEY (mainflux_thing, owner)
|
||||
PRIMARY KEY (mainflux_client, owner)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS unknown_configs (
|
||||
external_id TEXT UNIQUE NOT NULL,
|
||||
@@ -44,7 +44,7 @@ func Migration() *migrate.MemoryMigrationSource {
|
||||
config_id TEXT,
|
||||
config_owner VARCHAR(256),
|
||||
FOREIGN KEY (channel_id, channel_owner) REFERENCES channels (mainflux_channel, owner) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
FOREIGN KEY (config_id, config_owner) REFERENCES configs (mainflux_thing, owner) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
FOREIGN KEY (config_id, config_owner) REFERENCES configs (mainflux_client, owner) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
PRIMARY KEY (channel_id, channel_owner, config_id, config_owner)
|
||||
)`,
|
||||
},
|
||||
@@ -78,8 +78,8 @@ func Migration() *migrate.MemoryMigrationSource {
|
||||
{
|
||||
Id: "configs_4",
|
||||
Up: []string{
|
||||
`ALTER TABLE IF EXISTS configs RENAME COLUMN mainflux_thing TO magistrala_thing`,
|
||||
`ALTER TABLE IF EXISTS configs RENAME COLUMN mainflux_key TO magistrala_key`,
|
||||
`ALTER TABLE IF EXISTS configs RENAME COLUMN mainflux_client TO magistrala_client`,
|
||||
`ALTER TABLE IF EXISTS configs RENAME COLUMN mainflux_key TO magistrala_secret`,
|
||||
`ALTER TABLE IF EXISTS channels RENAME COLUMN mainflux_channel TO magistrala_channel`,
|
||||
},
|
||||
},
|
||||
@@ -100,7 +100,7 @@ func Migration() *migrate.MemoryMigrationSource {
|
||||
`ALTER TABLE IF EXISTS connections ADD COLUMN IF NOT EXISTS domain_id VARCHAR(256) NOT NULL`,
|
||||
`ALTER TABLE IF EXISTS connections ADD CONSTRAINT connections_pkey PRIMARY KEY (channel_id, config_id, domain_id)`,
|
||||
`ALTER TABLE IF EXISTS connections ADD FOREIGN KEY (channel_id, domain_id) REFERENCES channels (magistrala_channel, domain_id) ON DELETE CASCADE ON UPDATE CASCADE`,
|
||||
`ALTER TABLE IF EXISTS connections ADD FOREIGN KEY (config_id, domain_id) REFERENCES configs (magistrala_thing, domain_id) ON DELETE CASCADE ON UPDATE CASCADE`,
|
||||
`ALTER TABLE IF EXISTS connections ADD FOREIGN KEY (config_id, domain_id) REFERENCES configs (magistrala_client, domain_id) ON DELETE CASCADE ON UPDATE CASCADE`,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
+14
-14
@@ -16,13 +16,13 @@ import (
|
||||
// This is used as a response from ConfigReader and can easily be
|
||||
// replace with any other response format.
|
||||
type bootstrapRes struct {
|
||||
ThingID string `json:"thing_id"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []channelRes `json:"channels"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
Channels []channelRes `json:"channels"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
}
|
||||
|
||||
type channelRes struct {
|
||||
@@ -60,13 +60,13 @@ func (r reader) ReadConfig(cfg Config, secure bool) (interface{}, error) {
|
||||
}
|
||||
|
||||
res := bootstrapRes{
|
||||
ThingKey: cfg.ThingKey,
|
||||
ThingID: cfg.ThingID,
|
||||
Channels: channels,
|
||||
Content: cfg.Content,
|
||||
ClientCert: cfg.ClientCert,
|
||||
ClientKey: cfg.ClientKey,
|
||||
CACert: cfg.CACert,
|
||||
ClientID: cfg.ClientID,
|
||||
ClientSecret: cfg.ClientSecret,
|
||||
Channels: channels,
|
||||
Content: cfg.Content,
|
||||
ClientCert: cfg.ClientCert,
|
||||
ClientKey: cfg.ClientKey,
|
||||
CACert: cfg.CACert,
|
||||
}
|
||||
if secure {
|
||||
b, err := json.Marshal(res)
|
||||
|
||||
+14
-14
@@ -24,13 +24,13 @@ type readChan struct {
|
||||
}
|
||||
|
||||
type readResp struct {
|
||||
ThingID string `json:"thing_id"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []readChan `json:"channels"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
Channels []readChan `json:"channels"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
}
|
||||
|
||||
func dec(in []byte) ([]byte, error) {
|
||||
@@ -50,11 +50,11 @@ func dec(in []byte) ([]byte, error) {
|
||||
|
||||
func TestReadConfig(t *testing.T) {
|
||||
cfg := bootstrap.Config{
|
||||
ThingID: "mg_id",
|
||||
ClientCert: "client_cert",
|
||||
ClientKey: "client_key",
|
||||
CACert: "ca_cert",
|
||||
ThingKey: "mg_key",
|
||||
ClientID: "mg_id",
|
||||
ClientCert: "client_cert",
|
||||
ClientKey: "client_key",
|
||||
CACert: "ca_cert",
|
||||
ClientSecret: "mg_key",
|
||||
Channels: []bootstrap.Channel{
|
||||
{
|
||||
ID: "mg_id",
|
||||
@@ -65,8 +65,8 @@ func TestReadConfig(t *testing.T) {
|
||||
Content: "content",
|
||||
}
|
||||
ret := readResp{
|
||||
ThingID: "mg_id",
|
||||
ThingKey: "mg_key",
|
||||
ClientID: "mg_id",
|
||||
ClientSecret: "mg_key",
|
||||
Channels: []readChan{
|
||||
{
|
||||
ID: "mg_id",
|
||||
|
||||
+59
-62
@@ -19,9 +19,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrThings indicates failure to communicate with Magistrala Things service.
|
||||
// ErrClients indicates failure to communicate with Magistrala Clients service.
|
||||
// It can be due to networking error or invalid/unauthenticated request.
|
||||
ErrThings = errors.New("failed to receive response from Things service")
|
||||
ErrClients = errors.New("failed to receive response from Clients service")
|
||||
|
||||
// ErrExternalKey indicates a non-existent bootstrap configuration for given external key.
|
||||
ErrExternalKey = errors.New("failed to get bootstrap configuration for given external key")
|
||||
@@ -44,12 +44,12 @@ var (
|
||||
errUpdateChannel = errors.New("failed to update channel")
|
||||
errRemoveConfig = errors.New("failed to remove bootstrap configuration")
|
||||
errRemoveChannel = errors.New("failed to remove channel")
|
||||
errCreateThing = errors.New("failed to create thing")
|
||||
errConnectThing = errors.New("failed to connect thing")
|
||||
errDisconnectThing = errors.New("failed to disconnect thing")
|
||||
errCreateClient = errors.New("failed to create client")
|
||||
errConnectClient = errors.New("failed to connect client")
|
||||
errDisconnectClient = errors.New("failed to disconnect client")
|
||||
errCheckChannels = errors.New("failed to check if channels exists")
|
||||
errConnectionChannels = errors.New("failed to check channels connections")
|
||||
errThingNotFound = errors.New("failed to find thing")
|
||||
errClientNotFound = errors.New("failed to find client")
|
||||
errUpdateCert = errors.New("failed to update cert")
|
||||
)
|
||||
|
||||
@@ -60,10 +60,10 @@ var _ Service = (*bootstrapService)(nil)
|
||||
//
|
||||
//go:generate mockery --name Service --output=./mocks --filename service.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type Service interface {
|
||||
// Add adds new Thing Config to the user identified by the provided token.
|
||||
// Add adds new Client Config to the user identified by the provided token.
|
||||
Add(ctx context.Context, session mgauthn.Session, token string, cfg Config) (Config, error)
|
||||
|
||||
// View returns Thing Config with given ID belonging to the user identified by the given token.
|
||||
// View returns Client Config with given ID belonging to the user identified by the given token.
|
||||
View(ctx context.Context, session mgauthn.Session, id string) (Config, error)
|
||||
|
||||
// Update updates editable fields of the provided Config.
|
||||
@@ -71,7 +71,7 @@ type Service interface {
|
||||
|
||||
// UpdateCert updates an existing Config certificate and token.
|
||||
// A non-nil error is returned to indicate operation failure.
|
||||
UpdateCert(ctx context.Context, session mgauthn.Session, thingID, clientCert, clientKey, caCert string) (Config, error)
|
||||
UpdateCert(ctx context.Context, session mgauthn.Session, clientID, clientCert, clientKey, caCert string) (Config, error)
|
||||
|
||||
// UpdateConnections updates list of Channels related to given Config.
|
||||
UpdateConnections(ctx context.Context, session mgauthn.Session, token, id string, connections []string) error
|
||||
@@ -83,10 +83,10 @@ type Service interface {
|
||||
// Remove removes Config with specified token that belongs to the user identified by the given token.
|
||||
Remove(ctx context.Context, session mgauthn.Session, id string) error
|
||||
|
||||
// Bootstrap returns Config to the Thing with provided external ID using external key.
|
||||
// Bootstrap returns Config to the Client with provided external ID using external key.
|
||||
Bootstrap(ctx context.Context, externalKey, externalID string, secure bool) (Config, error)
|
||||
|
||||
// ChangeState changes state of the Thing with given thing ID and domain ID.
|
||||
// ChangeState changes state of the Client with given client ID and domain ID.
|
||||
ChangeState(ctx context.Context, session mgauthn.Session, token, id string, state State) error
|
||||
|
||||
// Methods RemoveConfig, UpdateChannel, and RemoveChannel are used as
|
||||
@@ -101,11 +101,11 @@ type Service interface {
|
||||
// RemoveChannelHandler removes Channel with id received from an event.
|
||||
RemoveChannelHandler(ctx context.Context, id string) error
|
||||
|
||||
// ConnectThingHandler changes state of the Config to active when connect event occurs.
|
||||
ConnectThingHandler(ctx context.Context, channelID, ThingID string) error
|
||||
// ConnectClientHandler changes state of the Config to active when connect event occurs.
|
||||
ConnectClientHandler(ctx context.Context, channelID, clientID string) error
|
||||
|
||||
// DisconnectThingHandler changes state of the Config to inactive when disconnect event occurs.
|
||||
DisconnectThingHandler(ctx context.Context, channelID, ThingID string) error
|
||||
// DisconnectClientHandler changes state of the Config to inactive when disconnect event occurs.
|
||||
DisconnectClientHandler(ctx context.Context, channelID, clientID string) error
|
||||
}
|
||||
|
||||
// ConfigReader is used to parse Config into format which will be encoded
|
||||
@@ -151,36 +151,36 @@ func (bs bootstrapService) Add(ctx context.Context, session mgauthn.Session, tok
|
||||
return Config{}, errors.Wrap(errConnectionChannels, err)
|
||||
}
|
||||
|
||||
id := cfg.ThingID
|
||||
mgThing, err := bs.thing(session.DomainID, id, token)
|
||||
id := cfg.ClientID
|
||||
mgClient, err := bs.client(session.DomainID, id, token)
|
||||
if err != nil {
|
||||
return Config{}, errors.Wrap(errThingNotFound, err)
|
||||
return Config{}, errors.Wrap(errClientNotFound, err)
|
||||
}
|
||||
|
||||
for _, channel := range cfg.Channels {
|
||||
if channel.DomainID != mgThing.DomainID {
|
||||
if channel.DomainID != mgClient.DomainID {
|
||||
return Config{}, errors.Wrap(svcerr.ErrMalformedEntity, errNotInSameDomain)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.ThingID = mgThing.ID
|
||||
cfg.ClientID = mgClient.ID
|
||||
cfg.DomainID = session.DomainID
|
||||
cfg.State = Inactive
|
||||
cfg.ThingKey = mgThing.Credentials.Secret
|
||||
cfg.ClientSecret = mgClient.Credentials.Secret
|
||||
|
||||
saved, err := bs.configs.Save(ctx, cfg, toConnect)
|
||||
if err != nil {
|
||||
// If id is empty, then a new thing has been created function - bs.thing(id, token)
|
||||
// So, on bootstrap config save error , delete the newly created thing.
|
||||
// If id is empty, then a new client has been created function - bs.client(id, token)
|
||||
// So, on bootstrap config save error , delete the newly created client.
|
||||
if id == "" {
|
||||
if errT := bs.sdk.DeleteThing(cfg.ThingID, cfg.DomainID, token); errT != nil {
|
||||
if errT := bs.sdk.DeleteClient(cfg.ClientID, cfg.DomainID, token); errT != nil {
|
||||
err = errors.Wrap(err, errT)
|
||||
}
|
||||
}
|
||||
return Config{}, errors.Wrap(ErrAddBootstrap, err)
|
||||
}
|
||||
|
||||
cfg.ThingID = saved
|
||||
cfg.ClientID = saved
|
||||
cfg.Channels = append(cfg.Channels, existing...)
|
||||
|
||||
return cfg, nil
|
||||
@@ -202,8 +202,8 @@ func (bs bootstrapService) Update(ctx context.Context, session mgauthn.Session,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs bootstrapService) UpdateCert(ctx context.Context, session mgauthn.Session, thingID, clientCert, clientKey, caCert string) (Config, error) {
|
||||
cfg, err := bs.configs.UpdateCert(ctx, session.DomainID, thingID, clientCert, clientKey, caCert)
|
||||
func (bs bootstrapService) UpdateCert(ctx context.Context, session mgauthn.Session, clientID, clientCert, clientKey, caCert string) (Config, error) {
|
||||
cfg, err := bs.configs.UpdateCert(ctx, session.DomainID, clientID, clientCert, clientKey, caCert)
|
||||
if err != nil {
|
||||
return Config{}, errors.Wrap(errUpdateCert, err)
|
||||
}
|
||||
@@ -238,21 +238,22 @@ func (bs bootstrapService) UpdateConnections(ctx context.Context, session mgauth
|
||||
}
|
||||
|
||||
for _, c := range disconnect {
|
||||
if err := bs.sdk.DisconnectThing(id, c, session.DomainID, token); err != nil {
|
||||
if err := bs.sdk.DisconnectClient(id, c, []string{"Publish", "Subscribe"}, session.DomainID, token); err != nil {
|
||||
if errors.Contains(err, repoerr.ErrNotFound) {
|
||||
continue
|
||||
}
|
||||
return ErrThings
|
||||
return ErrClients
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range connect {
|
||||
conIDs := mgsdk.Connection{
|
||||
ChannelID: c,
|
||||
ThingID: id,
|
||||
ChannelIDs: []string{c},
|
||||
ClientIDs: []string{id},
|
||||
Types: []string{"Publish", "Subscribe"},
|
||||
}
|
||||
if err := bs.sdk.Connect(conIDs, session.DomainID, token); err != nil {
|
||||
return ErrThings
|
||||
return ErrClients
|
||||
}
|
||||
}
|
||||
if err := bs.configs.UpdateConnections(ctx, session.DomainID, id, channels, connections); err != nil {
|
||||
@@ -266,7 +267,7 @@ func (bs bootstrapService) listClientIDs(ctx context.Context, userID string) ([]
|
||||
SubjectType: policies.UserType,
|
||||
Subject: userID,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ThingType,
|
||||
ObjectType: policies.ClientType,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(svcerr.ErrNotFound, err)
|
||||
@@ -280,12 +281,12 @@ func (bs bootstrapService) List(ctx context.Context, session mgauthn.Session, fi
|
||||
}
|
||||
|
||||
// Handle non-admin users
|
||||
thingIDs, err := bs.listClientIDs(ctx, session.DomainUserID)
|
||||
clientIDs, err := bs.listClientIDs(ctx, session.DomainUserID)
|
||||
if err != nil {
|
||||
return ConfigsPage{}, errors.Wrap(svcerr.ErrNotFound, err)
|
||||
}
|
||||
|
||||
if len(thingIDs) == 0 {
|
||||
if len(clientIDs) == 0 {
|
||||
return ConfigsPage{
|
||||
Total: 0,
|
||||
Offset: offset,
|
||||
@@ -294,7 +295,7 @@ func (bs bootstrapService) List(ctx context.Context, session mgauthn.Session, fi
|
||||
}, nil
|
||||
}
|
||||
|
||||
return bs.configs.RetrieveAll(ctx, session.DomainID, thingIDs, filter, offset, limit), nil
|
||||
return bs.configs.RetrieveAll(ctx, session.DomainID, clientIDs, filter, offset, limit), nil
|
||||
}
|
||||
|
||||
func (bs bootstrapService) Remove(ctx context.Context, session mgauthn.Session, id string) error {
|
||||
@@ -336,25 +337,21 @@ func (bs bootstrapService) ChangeState(ctx context.Context, session mgauthn.Sess
|
||||
switch state {
|
||||
case Active:
|
||||
for _, c := range cfg.Channels {
|
||||
conIDs := mgsdk.Connection{
|
||||
ChannelID: c.ID,
|
||||
ThingID: cfg.ThingID,
|
||||
}
|
||||
if err := bs.sdk.Connect(conIDs, session.DomainID, token); err != nil {
|
||||
if err := bs.sdk.ConnectClient(cfg.ClientID, c.ID, []string{"Publish", "Subscribe"}, session.DomainID, token); err != nil {
|
||||
// Ignore conflict errors as they indicate the connection already exists.
|
||||
if errors.Contains(err, svcerr.ErrConflict) {
|
||||
continue
|
||||
}
|
||||
return ErrThings
|
||||
return ErrClients
|
||||
}
|
||||
}
|
||||
case Inactive:
|
||||
for _, c := range cfg.Channels {
|
||||
if err := bs.sdk.DisconnectThing(cfg.ThingID, c.ID, session.DomainID, token); err != nil {
|
||||
if err := bs.sdk.DisconnectClient(cfg.ClientID, c.ID, []string{"Publish", "Subscribe"}, session.DomainID, token); err != nil {
|
||||
if errors.Contains(err, repoerr.ErrNotFound) {
|
||||
continue
|
||||
}
|
||||
return ErrThings
|
||||
return ErrClients
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,7 +369,7 @@ func (bs bootstrapService) UpdateChannelHandler(ctx context.Context, channel Cha
|
||||
}
|
||||
|
||||
func (bs bootstrapService) RemoveConfigHandler(ctx context.Context, id string) error {
|
||||
if err := bs.configs.RemoveThing(ctx, id); err != nil {
|
||||
if err := bs.configs.RemoveClient(ctx, id); err != nil {
|
||||
return errors.Wrap(errRemoveConfig, err)
|
||||
}
|
||||
return nil
|
||||
@@ -385,41 +382,41 @@ func (bs bootstrapService) RemoveChannelHandler(ctx context.Context, id string)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs bootstrapService) ConnectThingHandler(ctx context.Context, channelID, thingID string) error {
|
||||
if err := bs.configs.ConnectThing(ctx, channelID, thingID); err != nil {
|
||||
return errors.Wrap(errConnectThing, err)
|
||||
func (bs bootstrapService) ConnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
if err := bs.configs.ConnectClient(ctx, channelID, clientID); err != nil {
|
||||
return errors.Wrap(errConnectClient, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs bootstrapService) DisconnectThingHandler(ctx context.Context, channelID, thingID string) error {
|
||||
if err := bs.configs.DisconnectThing(ctx, channelID, thingID); err != nil {
|
||||
return errors.Wrap(errDisconnectThing, err)
|
||||
func (bs bootstrapService) DisconnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
if err := bs.configs.DisconnectClient(ctx, channelID, clientID); err != nil {
|
||||
return errors.Wrap(errDisconnectClient, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Method thing retrieves Magistrala Thing creating one if an empty ID is passed.
|
||||
func (bs bootstrapService) thing(domainID, id, token string) (mgsdk.Thing, error) {
|
||||
// If Thing ID is not provided, then create new thing.
|
||||
// Method client retrieves Magistrala Client creating one if an empty ID is passed.
|
||||
func (bs bootstrapService) client(domainID, id, token string) (mgsdk.Client, error) {
|
||||
// If Client ID is not provided, then create new client.
|
||||
if id == "" {
|
||||
id, err := bs.idProvider.ID()
|
||||
if err != nil {
|
||||
return mgsdk.Thing{}, errors.Wrap(errCreateThing, err)
|
||||
return mgsdk.Client{}, errors.Wrap(errCreateClient, err)
|
||||
}
|
||||
thing, sdkErr := bs.sdk.CreateThing(mgsdk.Thing{ID: id, Name: "Bootstrapped Thing " + id}, domainID, token)
|
||||
client, sdkErr := bs.sdk.CreateClient(mgsdk.Client{ID: id, Name: "Bootstrapped Client " + id}, domainID, token)
|
||||
if sdkErr != nil {
|
||||
return mgsdk.Thing{}, errors.Wrap(errCreateThing, sdkErr)
|
||||
return mgsdk.Client{}, errors.Wrap(errCreateClient, sdkErr)
|
||||
}
|
||||
return thing, nil
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// If Thing ID is provided, then retrieve thing
|
||||
thing, sdkErr := bs.sdk.Thing(id, domainID, token)
|
||||
// If Client ID is provided, then retrieve client
|
||||
client, sdkErr := bs.sdk.Client(id, domainID, token)
|
||||
if sdkErr != nil {
|
||||
return mgsdk.Thing{}, errors.Wrap(ErrThings, sdkErr)
|
||||
return mgsdk.Client{}, errors.Wrap(ErrClients, sdkErr)
|
||||
}
|
||||
return thing, nil
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (bs bootstrapService) connectionChannels(channels, existing []string, domainID, token string) ([]Channel, error) {
|
||||
|
||||
+104
-104
@@ -50,12 +50,12 @@ var (
|
||||
}
|
||||
|
||||
config = bootstrap.Config{
|
||||
ThingID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ThingKey: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalKey: testsutil.GenerateUUID(&testing.T{}),
|
||||
Channels: []bootstrap.Channel{channel},
|
||||
Content: "config",
|
||||
ClientID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ClientSecret: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalID: testsutil.GenerateUUID(&testing.T{}),
|
||||
ExternalKey: testsutil.GenerateUUID(&testing.T{}),
|
||||
Channels: []bootstrap.Channel{channel},
|
||||
Content: "config",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestAdd(t *testing.T) {
|
||||
svc := newService()
|
||||
|
||||
neID := config
|
||||
neID.ThingID = "non-existent"
|
||||
neID.ClientID = "non-existent"
|
||||
|
||||
wrongChannels := config
|
||||
ch := channel
|
||||
@@ -106,12 +106,12 @@ func TestAdd(t *testing.T) {
|
||||
session mgauthn.Session
|
||||
userID string
|
||||
domainID string
|
||||
thingErr error
|
||||
createThingErr error
|
||||
clientErr error
|
||||
createClientErr error
|
||||
channelErr error
|
||||
listExistingErr error
|
||||
saveErr error
|
||||
deleteThingErr error
|
||||
deleteClientErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -123,13 +123,13 @@ func TestAdd(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "add a config with an invalid ID",
|
||||
config: neID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
thingErr: errors.NewSDKError(svcerr.ErrNotFound),
|
||||
err: svcerr.ErrNotFound,
|
||||
desc: "add a config with an invalid ID",
|
||||
config: neID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
clientErr: errors.NewSDKError(svcerr.ErrNotFound),
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "add a config with invalid list of channels",
|
||||
@@ -152,9 +152,9 @@ func TestAdd(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
tc.session = mgauthn.Session{UserID: tc.userID, DomainID: tc.domainID, DomainUserID: validID}
|
||||
repoCall := sdk.On("Thing", tc.config.ThingID, mock.Anything, tc.token).Return(mgsdk.Thing{ID: tc.config.ThingID, Credentials: mgsdk.ClientCredentials{Secret: tc.config.ThingKey}}, tc.thingErr)
|
||||
repoCall1 := sdk.On("CreateThing", mock.Anything, tc.domainID, tc.token).Return(mgsdk.Thing{}, tc.createThingErr)
|
||||
repoCall2 := sdk.On("DeleteThing", tc.config.ThingID, tc.domainID, tc.token).Return(tc.deleteThingErr)
|
||||
repoCall := sdk.On("Client", tc.config.ClientID, mock.Anything, tc.token).Return(mgsdk.Client{ID: tc.config.ClientID, Credentials: mgsdk.ClientCredentials{Secret: tc.config.ClientSecret}}, tc.clientErr)
|
||||
repoCall1 := sdk.On("CreateClient", mock.Anything, tc.domainID, tc.token).Return(mgsdk.Client{}, tc.createClientErr)
|
||||
repoCall2 := sdk.On("DeleteClient", tc.config.ClientID, tc.domainID, tc.token).Return(tc.deleteClientErr)
|
||||
repoCall3 := boot.On("ListExisting", context.Background(), tc.domainID, mock.Anything).Return(tc.config.Channels, tc.listExistingErr)
|
||||
repoCall4 := boot.On("Save", context.Background(), mock.Anything, mock.Anything).Return(mock.Anything, tc.saveErr)
|
||||
_, err := svc.Add(context.Background(), tc.session, tc.token, tc.config)
|
||||
@@ -172,53 +172,53 @@ func TestView(t *testing.T) {
|
||||
svc := newService()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
configID string
|
||||
userID string
|
||||
domain string
|
||||
thingDomain string
|
||||
token string
|
||||
session mgauthn.Session
|
||||
retrieveErr error
|
||||
thingErr error
|
||||
channelErr error
|
||||
err error
|
||||
desc string
|
||||
configID string
|
||||
userID string
|
||||
domain string
|
||||
clientDomain string
|
||||
token string
|
||||
session mgauthn.Session
|
||||
retrieveErr error
|
||||
clientErr error
|
||||
channelErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "view an existing config",
|
||||
configID: config.ThingID,
|
||||
userID: validID,
|
||||
thingDomain: domainID,
|
||||
domain: domainID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
desc: "view an existing config",
|
||||
configID: config.ClientID,
|
||||
userID: validID,
|
||||
clientDomain: domainID,
|
||||
domain: domainID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "view a non-existing config",
|
||||
configID: unknown,
|
||||
userID: validID,
|
||||
thingDomain: domainID,
|
||||
domain: domainID,
|
||||
token: validToken,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
desc: "view a non-existing config",
|
||||
configID: unknown,
|
||||
userID: validID,
|
||||
clientDomain: domainID,
|
||||
domain: domainID,
|
||||
token: validToken,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "view a config with invalid domain",
|
||||
configID: config.ThingID,
|
||||
userID: validID,
|
||||
thingDomain: invalidDomainID,
|
||||
domain: invalidDomainID,
|
||||
token: validToken,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
desc: "view a config with invalid domain",
|
||||
configID: config.ClientID,
|
||||
userID: validID,
|
||||
clientDomain: invalidDomainID,
|
||||
domain: invalidDomainID,
|
||||
token: validToken,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
tc.session = mgauthn.Session{UserID: tc.userID, DomainID: tc.domain, DomainUserID: validID}
|
||||
repoCall := boot.On("RetrieveByID", context.Background(), tc.thingDomain, tc.configID).Return(config, tc.retrieveErr)
|
||||
repoCall := boot.On("RetrieveByID", context.Background(), tc.clientDomain, tc.configID).Return(config, tc.retrieveErr)
|
||||
_, err := svc.View(context.Background(), tc.session, tc.configID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
repoCall.Unset()
|
||||
@@ -239,7 +239,7 @@ func TestUpdate(t *testing.T) {
|
||||
modifiedCreated.Name = "new name"
|
||||
|
||||
nonExisting := c
|
||||
nonExisting.ThingID = unknown
|
||||
nonExisting.ClientID = unknown
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -304,7 +304,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
session mgauthn.Session
|
||||
userID string
|
||||
domainID string
|
||||
thingID string
|
||||
clientID string
|
||||
clientCert string
|
||||
clientKey string
|
||||
caCert string
|
||||
@@ -318,24 +318,24 @@ func TestUpdateCert(t *testing.T) {
|
||||
desc: "update certs for the valid config",
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
thingID: c.ThingID,
|
||||
clientID: c.ClientID,
|
||||
clientCert: "newCert",
|
||||
clientKey: "newKey",
|
||||
caCert: "newCert",
|
||||
token: validToken,
|
||||
expectedConfig: bootstrap.Config{
|
||||
Name: c.Name,
|
||||
ThingKey: c.ThingKey,
|
||||
Channels: c.Channels,
|
||||
ExternalID: c.ExternalID,
|
||||
ExternalKey: c.ExternalKey,
|
||||
Content: c.Content,
|
||||
State: c.State,
|
||||
DomainID: c.DomainID,
|
||||
ThingID: c.ThingID,
|
||||
ClientCert: "newCert",
|
||||
CACert: "newCert",
|
||||
ClientKey: "newKey",
|
||||
Name: c.Name,
|
||||
ClientSecret: c.ClientSecret,
|
||||
Channels: c.Channels,
|
||||
ExternalID: c.ExternalID,
|
||||
ExternalKey: c.ExternalKey,
|
||||
Content: c.Content,
|
||||
State: c.State,
|
||||
DomainID: c.DomainID,
|
||||
ClientID: c.ClientID,
|
||||
ClientCert: "newCert",
|
||||
CACert: "newCert",
|
||||
ClientKey: "newKey",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
@@ -343,7 +343,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
desc: "update cert for a non-existing config",
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
thingID: "empty",
|
||||
clientID: "empty",
|
||||
clientCert: "newCert",
|
||||
clientKey: "newKey",
|
||||
caCert: "newCert",
|
||||
@@ -358,7 +358,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
tc.session = mgauthn.Session{UserID: tc.userID, DomainID: tc.domainID, DomainUserID: validID}
|
||||
repoCall := boot.On("UpdateCert", context.Background(), mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.expectedConfig, tc.updateErr)
|
||||
cfg, err := svc.UpdateCert(context.Background(), tc.session, tc.thingID, tc.clientCert, tc.clientKey, tc.caCert)
|
||||
cfg, err := svc.UpdateCert(context.Background(), tc.session, tc.clientID, tc.clientCert, tc.clientKey, tc.caCert)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
sort.Slice(cfg.Channels, func(i, j int) bool {
|
||||
return cfg.Channels[i].ID < cfg.Channels[j].ID
|
||||
@@ -393,7 +393,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
domainID string
|
||||
connections []string
|
||||
updateErr error
|
||||
thingErr error
|
||||
clientErr error
|
||||
channelErr error
|
||||
retrieveErr error
|
||||
listErr error
|
||||
@@ -404,7 +404,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
state: c.State,
|
||||
connections: []string{ch.ID},
|
||||
err: nil,
|
||||
@@ -414,7 +414,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
id: activeConf.ThingID,
|
||||
id: activeConf.ClientID,
|
||||
state: activeConf.State,
|
||||
connections: []string{ch.ID},
|
||||
err: nil,
|
||||
@@ -424,7 +424,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
connections: []string{"wrong"},
|
||||
channelErr: errors.NewSDKError(svcerr.ErrNotFound),
|
||||
err: svcerr.ErrNotFound,
|
||||
@@ -451,9 +451,9 @@ func TestUpdateConnections(t *testing.T) {
|
||||
func TestList(t *testing.T) {
|
||||
svc := newService()
|
||||
|
||||
numThings := 101
|
||||
numClients := 101
|
||||
var saved []bootstrap.Config
|
||||
for i := 0; i < numThings; i++ {
|
||||
for i := 0; i < numClients; i++ {
|
||||
c := config
|
||||
c.ExternalID = testsutil.GenerateUUID(t)
|
||||
c.ExternalKey = testsutil.GenerateUUID(t)
|
||||
@@ -722,7 +722,7 @@ func TestList(t *testing.T) {
|
||||
SubjectType: policysvc.UserType,
|
||||
Subject: tc.userID,
|
||||
Permission: policysvc.ViewPermission,
|
||||
ObjectType: policysvc.ThingType,
|
||||
ObjectType: policysvc.ClientType,
|
||||
}).Return(tc.listObjectsResponse, tc.listObjectsErr)
|
||||
repoCall := boot.On("RetrieveAll", context.Background(), mock.Anything, mock.Anything, tc.filter, tc.offset, tc.limit).Return(tc.config, tc.retrieveErr)
|
||||
|
||||
@@ -752,7 +752,7 @@ func TestRemove(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "remove an existing config",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -760,7 +760,7 @@ func TestRemove(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "remove removed config",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -768,7 +768,7 @@ func TestRemove(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "remove a config with failed remove",
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -889,7 +889,7 @@ func TestChangeState(t *testing.T) {
|
||||
{
|
||||
desc: "change state to Active",
|
||||
state: bootstrap.Active,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -898,7 +898,7 @@ func TestChangeState(t *testing.T) {
|
||||
{
|
||||
desc: "change state to current state",
|
||||
state: bootstrap.Active,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -907,7 +907,7 @@ func TestChangeState(t *testing.T) {
|
||||
{
|
||||
desc: "change state to Inactive",
|
||||
state: bootstrap.Inactive,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -916,17 +916,17 @@ func TestChangeState(t *testing.T) {
|
||||
{
|
||||
desc: "change state with failed Connect",
|
||||
state: bootstrap.Active,
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
connectErr: errors.NewSDKError(bootstrap.ErrThings),
|
||||
err: bootstrap.ErrThings,
|
||||
connectErr: errors.NewSDKError(bootstrap.ErrClients),
|
||||
err: bootstrap.ErrClients,
|
||||
},
|
||||
{
|
||||
desc: "change state with invalid state",
|
||||
state: bootstrap.State(2),
|
||||
id: c.ThingID,
|
||||
id: c.ClientID,
|
||||
token: validToken,
|
||||
userID: validID,
|
||||
domainID: domainID,
|
||||
@@ -939,7 +939,7 @@ func TestChangeState(t *testing.T) {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
tc.session = mgauthn.Session{UserID: tc.userID, DomainID: tc.domainID, DomainUserID: validID}
|
||||
repoCall := boot.On("RetrieveByID", context.Background(), tc.domainID, tc.id).Return(c, tc.retrieveErr)
|
||||
sdkCall := sdk.On("Connect", mock.Anything, mock.Anything, mock.Anything).Return(tc.connectErr)
|
||||
sdkCall := sdk.On("ConnectClient", mock.Anything, mock.Anything, []string{"Publish", "Subscribe"}, mock.Anything, tc.token).Return(tc.connectErr)
|
||||
repoCall1 := boot.On("ChangeState", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.stateErr)
|
||||
err := svc.ChangeState(context.Background(), tc.session, tc.token, tc.id, tc.state)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
@@ -1026,7 +1026,7 @@ func TestRemoveConfigHandler(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "remove an existing config",
|
||||
id: config.ThingID,
|
||||
id: config.ClientID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@@ -1038,7 +1038,7 @@ func TestRemoveConfigHandler(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
repoCall := boot.On("RemoveThing", context.Background(), mock.Anything).Return(tc.err)
|
||||
repoCall := boot.On("RemoveClient", context.Background(), mock.Anything).Return(tc.err)
|
||||
err := svc.RemoveConfigHandler(context.Background(), tc.id)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
repoCall.Unset()
|
||||
@@ -1046,66 +1046,66 @@ func TestRemoveConfigHandler(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectThingsHandler(t *testing.T) {
|
||||
func TestConnectClientHandler(t *testing.T) {
|
||||
svc := newService()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
clientID string
|
||||
channelID string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "connect",
|
||||
channelID: channel.ID,
|
||||
thingID: config.ThingID,
|
||||
clientID: config.ClientID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "connect connected",
|
||||
channelID: channel.ID,
|
||||
thingID: config.ThingID,
|
||||
clientID: config.ClientID,
|
||||
err: svcerr.ErrAddPolicies,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
repoCall := boot.On("ConnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err)
|
||||
err := svc.ConnectThingHandler(context.Background(), tc.channelID, tc.thingID)
|
||||
repoCall := boot.On("ConnectClient", context.Background(), mock.Anything, mock.Anything).Return(tc.err)
|
||||
err := svc.ConnectClientHandler(context.Background(), tc.channelID, tc.clientID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
repoCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectThingsHandler(t *testing.T) {
|
||||
func TestDisconnectClientsHandler(t *testing.T) {
|
||||
svc := newService()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
clientID string
|
||||
channelID string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "disconnect",
|
||||
channelID: channel.ID,
|
||||
thingID: config.ThingID,
|
||||
clientID: config.ClientID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "disconnect disconnected",
|
||||
channelID: channel.ID,
|
||||
thingID: config.ThingID,
|
||||
clientID: config.ClientID,
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
repoCall := boot.On("DisconnectThing", context.Background(), mock.Anything, mock.Anything).Return(tc.err)
|
||||
err := svc.DisconnectThingHandler(context.Background(), tc.channelID, tc.thingID)
|
||||
repoCall := boot.On("DisconnectClient", context.Background(), mock.Anything, mock.Anything).Return(tc.err)
|
||||
err := svc.DisconnectClientHandler(context.Background(), tc.channelID, tc.clientID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
repoCall.Unset()
|
||||
})
|
||||
|
||||
+5
-5
@@ -6,18 +6,18 @@ package bootstrap
|
||||
import "strconv"
|
||||
|
||||
const (
|
||||
// Inactive Thing is created, but not able to exchange messages using Magistrala.
|
||||
// Inactive Client is created, but not able to exchange messages using Magistrala.
|
||||
Inactive State = iota
|
||||
// Active Thing is created, configured, and whitelisted.
|
||||
// Active Client is created, configured, and whitelisted.
|
||||
Active
|
||||
)
|
||||
|
||||
// State represents corresponding Magistrala Thing state. The possible Config States
|
||||
// State represents corresponding Magistrala Client state. The possible Config States
|
||||
// as well as description of what that State represents are given in the table:
|
||||
// | State | What it means |
|
||||
// |----------+--------------------------------------------------------------------------------|
|
||||
// | Inactive | Thing is created, but isn't able to communicate over Magistrala |
|
||||
// | Active | Thing is able to communicate using Magistrala |.
|
||||
// | Inactive | Client is created, but isn't able to communicate over Magistrala |
|
||||
// | Active | Client is able to communicate using Magistrala |.
|
||||
type State int
|
||||
|
||||
// String returns string representation of State.
|
||||
|
||||
@@ -27,7 +27,7 @@ func New(svc bootstrap.Service, tracer trace.Tracer) bootstrap.Service {
|
||||
// Add traces the "Add" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) Add(ctx context.Context, session mgauthn.Session, token string, cfg bootstrap.Config) (bootstrap.Config, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_register_user", trace.WithAttributes(
|
||||
attribute.String("thing_id", cfg.ThingID),
|
||||
attribute.String("client_id", cfg.ClientID),
|
||||
attribute.String("domain_id ", cfg.DomainID),
|
||||
attribute.String("name", cfg.Name),
|
||||
attribute.String("external_id", cfg.ExternalID),
|
||||
@@ -54,7 +54,7 @@ func (tm *tracingMiddleware) Update(ctx context.Context, session mgauthn.Session
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_update_user", trace.WithAttributes(
|
||||
attribute.String("name", cfg.Name),
|
||||
attribute.String("content", cfg.Content),
|
||||
attribute.String("thing_id", cfg.ThingID),
|
||||
attribute.String("client_id", cfg.ClientID),
|
||||
attribute.String("domain_id ", cfg.DomainID),
|
||||
))
|
||||
defer span.End()
|
||||
@@ -63,13 +63,13 @@ func (tm *tracingMiddleware) Update(ctx context.Context, session mgauthn.Session
|
||||
}
|
||||
|
||||
// UpdateCert traces the "UpdateCert" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
func (tm *tracingMiddleware) UpdateCert(ctx context.Context, session mgauthn.Session, clientID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_update_cert", trace.WithAttributes(
|
||||
attribute.String("thing_id", thingID),
|
||||
attribute.String("client_id", clientID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.UpdateCert(ctx, session, thingID, clientCert, clientKey, caCert)
|
||||
return tm.svc.UpdateCert(ctx, session, clientID, clientCert, clientKey, caCert)
|
||||
}
|
||||
|
||||
// UpdateConnections traces the "UpdateConnections" operation of the wrapped bootstrap.Service.
|
||||
@@ -159,24 +159,24 @@ func (tm *tracingMiddleware) RemoveChannelHandler(ctx context.Context, id string
|
||||
return tm.svc.RemoveChannelHandler(ctx, id)
|
||||
}
|
||||
|
||||
// ConnectThingHandler traces the "ConnectThingHandler" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) ConnectThingHandler(ctx context.Context, channelID, thingID string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_connect_thing_handler", trace.WithAttributes(
|
||||
// ConnectClientHandler traces the "ConnectClientHandler" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) ConnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_connect_client_handler", trace.WithAttributes(
|
||||
attribute.String("channel_id", channelID),
|
||||
attribute.String("thing_id", thingID),
|
||||
attribute.String("client_id", clientID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.ConnectThingHandler(ctx, channelID, thingID)
|
||||
return tm.svc.ConnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
// DisconnectThingHandler traces the "DisconnectThingHandler" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) DisconnectThingHandler(ctx context.Context, channelID, thingID string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_disconnect_thing_handler", trace.WithAttributes(
|
||||
// DisconnectClientHandler traces the "DisconnectClientHandler" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) DisconnectClientHandler(ctx context.Context, channelID, clientID string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_disconnect_client_handler", trace.WithAttributes(
|
||||
attribute.String("channel_id", channelID),
|
||||
attribute.String("thing_id", thingID),
|
||||
attribute.String("client_id", clientID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.DisconnectThingHandler(ctx, channelID, thingID)
|
||||
return tm.svc.DisconnectClientHandler(ctx, channelID, clientID)
|
||||
}
|
||||
|
||||
+43
-43
@@ -1,6 +1,6 @@
|
||||
# Certs Service
|
||||
|
||||
Issues certificates for things. `Certs` service can create certificates to be used when `Magistrala` is deployed to support mTLS.
|
||||
Issues certificates for clients. `Certs` service can create certificates to be used when `Magistrala` is deployed to support mTLS.
|
||||
Certificate service can create certificates using PKI mode - where certificates issued by PKI, when you deploy `Vault` as PKI certificate management `cert` service will proxy requests to `Vault` previously checking access rights and saving info on successfully created certificate.
|
||||
|
||||
## PKI mode
|
||||
@@ -16,60 +16,60 @@ MG_CERTS_VAULT_HOST=<https://vault-domain:8200>
|
||||
MG_CERTS_VAULT_NAMESPACE=<vault_namespace>
|
||||
MG_CERTS_VAULT_APPROLE_ROLEID=<vault_approle_roleid>
|
||||
MG_CERTS_VAULT_APPROLE_SECRET=<vault_approle_sceret>
|
||||
MG_CERTS_VAULT_THINGS_CERTS_PKI_PATH=<vault_things_certs_pki_path>
|
||||
MG_CERTS_VAULT_THINGS_CERTS_PKI_ROLE_NAME=<vault_things_certs_issue_role_name>
|
||||
MG_CERTS_VAULT_CLIENTS_CERTS_PKI_PATH=<vault_clients_certs_pki_path>
|
||||
MG_CERTS_VAULT_CLIENTS_CERTS_PKI_ROLE_NAME=<vault_clients_certs_issue_role_name>
|
||||
```
|
||||
|
||||
The certificates can also be revoked using `certs` service. To revoke a certificate you need to provide `thing_id` of the thing for which the certificate was issued.
|
||||
The certificates can also be revoked using `certs` service. To revoke a certificate you need to provide `client_id` of the client for which the certificate was issued.
|
||||
|
||||
```bash
|
||||
curl -s -S -X DELETE http://localhost:9019/certs/revoke -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' -d '{"thing_id":"c30b8842-507c-4bcd-973c-74008cef3be5"}'
|
||||
curl -s -S -X DELETE http://localhost:9019/certs/revoke -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' -d '{"client_id":"c30b8842-507c-4bcd-973c-74008cef3be5"}'
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.
|
||||
|
||||
| Variable | Description | Default |
|
||||
| :---------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
||||
| MG_CERTS_LOG_LEVEL | Log level for the Certs (debug, info, warn, error) | info |
|
||||
| MG_CERTS_HTTP_HOST | Service Certs host | "" |
|
||||
| MG_CERTS_HTTP_PORT | Service Certs port | 9019 |
|
||||
| MG_CERTS_HTTP_SERVER_CERT | Path to the PEM encoded server certificate file | "" |
|
||||
| MG_CERTS_HTTP_SERVER_KEY | Path to the PEM encoded server key file | "" |
|
||||
| MG_AUTH_GRPC_URL | Auth service gRPC URL | [localhost:8181](localhost:8181) |
|
||||
| MG_AUTH_GRPC_TIMEOUT | Auth service gRPC request timeout in seconds | 1s |
|
||||
| MG_AUTH_GRPC_CLIENT_CERT | Path to the PEM encoded auth service gRPC client certificate file | "" |
|
||||
| MG_AUTH_GRPC_CLIENT_KEY | Path to the PEM encoded auth service gRPC client key file | "" |
|
||||
| MG_AUTH_GRPC_SERVER_CERTS | Path to the PEM encoded auth server gRPC server trusted CA certificate file | "" |
|
||||
| MG_CERTS_SIGN_CA_PATH | Path to the PEM encoded CA certificate file | ca.crt |
|
||||
| MG_CERTS_SIGN_CA_KEY_PATH | Path to the PEM encoded CA key file | ca.key |
|
||||
| MG_CERTS_VAULT_HOST | Vault host | http://vault:8200 |
|
||||
| MG_CERTS_VAULT_NAMESPACE | Vault namespace in which pki is present | magistrala |
|
||||
| MG_CERTS_VAULT_APPROLE_ROLEID | Vault AppRole auth RoleID | magistrala |
|
||||
| MG_CERTS_VAULT_APPROLE_SECRET | Vault AppRole auth Secret | magistrala |
|
||||
| MG_CERTS_VAULT_THINGS_CERTS_PKI_PATH | Vault PKI path for issuing Things Certificates | pki_int |
|
||||
| MG_CERTS_VAULT_THINGS_CERTS_PKI_ROLE_NAME | Vault PKI Role Name for issuing Things Certificates | magistrala_things_certs |
|
||||
| MG_CERTS_DB_HOST | Database host | localhost |
|
||||
| MG_CERTS_DB_PORT | Database port | 5432 |
|
||||
| MG_CERTS_DB_PASS | Database password | magistrala |
|
||||
| MG_CERTS_DB_USER | Database user | magistrala |
|
||||
| MG_CERTS_DB_NAME | Database name | certs |
|
||||
| MG_CERTS_DB_SSL_MODE | Database SSL mode | disable |
|
||||
| MG_CERTS_DB_SSL_CERT | Database SSL certificate | "" |
|
||||
| MG_CERTS_DB_SSL_KEY | Database SSL key | "" |
|
||||
| MG_CERTS_DB_SSL_ROOT_CERT | Database SSL root certificate | "" |
|
||||
| MG_THINGS_URL | Things service URL | [localhost:9000](localhost:9000) |
|
||||
| MG_JAEGER_URL | Jaeger server URL | [http://localhost:4318/v1/traces](http://localhost:4318//v1/traces) |
|
||||
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
|
||||
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server | true |
|
||||
| MG_CERTS_INSTANCE_ID | Service instance ID | "" |
|
||||
| Variable | Description | Default |
|
||||
| :----------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| MG_CERTS_LOG_LEVEL | Log level for the Certs (debug, info, warn, error) | info |
|
||||
| MG_CERTS_HTTP_HOST | Service Certs host | "" |
|
||||
| MG_CERTS_HTTP_PORT | Service Certs port | 9019 |
|
||||
| MG_CERTS_HTTP_SERVER_CERT | Path to the PEM encoded server certificate file | "" |
|
||||
| MG_CERTS_HTTP_SERVER_KEY | Path to the PEM encoded server key file | "" |
|
||||
| MG_AUTH_GRPC_URL | Auth service gRPC URL | [localhost:8181](localhost:8181) |
|
||||
| MG_AUTH_GRPC_TIMEOUT | Auth service gRPC request timeout in seconds | 1s |
|
||||
| MG_AUTH_GRPC_CLIENT_CERT | Path to the PEM encoded auth service gRPC client certificate file | "" |
|
||||
| MG_AUTH_GRPC_CLIENT_KEY | Path to the PEM encoded auth service gRPC client key file | "" |
|
||||
| MG_AUTH_GRPC_SERVER_CERTS | Path to the PEM encoded auth server gRPC server trusted CA certificate file | "" |
|
||||
| MG_CERTS_SIGN_CA_PATH | Path to the PEM encoded CA certificate file | ca.crt |
|
||||
| MG_CERTS_SIGN_CA_KEY_PATH | Path to the PEM encoded CA key file | ca.key |
|
||||
| MG_CERTS_VAULT_HOST | Vault host | http://vault:8200 |
|
||||
| MG_CERTS_VAULT_NAMESPACE | Vault namespace in which pki is present | magistrala |
|
||||
| MG_CERTS_VAULT_APPROLE_ROLEID | Vault AppRole auth RoleID | magistrala |
|
||||
| MG_CERTS_VAULT_APPROLE_SECRET | Vault AppRole auth Secret | magistrala |
|
||||
| MG_CERTS_VAULT_CLIENTS_CERTS_PKI_PATH | Vault PKI path for issuing Clients Certificates | pki_int |
|
||||
| MG_CERTS_VAULT_CLIENTS_CERTS_PKI_ROLE_NAME | Vault PKI Role Name for issuing Clients Certificates | magistrala_clients_certs |
|
||||
| MG_CERTS_DB_HOST | Database host | localhost |
|
||||
| MG_CERTS_DB_PORT | Database port | 5432 |
|
||||
| MG_CERTS_DB_PASS | Database password | magistrala |
|
||||
| MG_CERTS_DB_USER | Database user | magistrala |
|
||||
| MG_CERTS_DB_NAME | Database name | certs |
|
||||
| MG_CERTS_DB_SSL_MODE | Database SSL mode | disable |
|
||||
| MG_CERTS_DB_SSL_CERT | Database SSL certificate | "" |
|
||||
| MG_CERTS_DB_SSL_KEY | Database SSL key | "" |
|
||||
| MG_CERTS_DB_SSL_ROOT_CERT | Database SSL root certificate | "" |
|
||||
| MG_CLIENTS_URL | Clients service URL | [localhost:9000](localhost:9000) |
|
||||
| MG_JAEGER_URL | Jaeger server URL | [http://localhost:4318/v1/traces](http://localhost:4318//v1/traces) |
|
||||
| MG_JAEGER_TRACE_RATIO | Jaeger sampling ratio | 1.0 |
|
||||
| MG_SEND_TELEMETRY | Send telemetry to magistrala call home server | true |
|
||||
| MG_CERTS_INSTANCE_ID | Service instance ID | "" |
|
||||
|
||||
## Deployment
|
||||
|
||||
The service is distributed as Docker container. Check the [`certs`](https://github.com/absmach/magistrala/blob/main/docker/addons/bootstrap/docker-compose.yml) service section in docker-compose file to see how the service is deployed.
|
||||
|
||||
Running this service outside of container requires working instance of the auth service, things service, postgres database, vault and Jaeger server.
|
||||
Running this service outside of container requires working instance of the auth service, clients service, postgres database, vault and Jaeger server.
|
||||
To start the service outside of the container, execute the following shell script:
|
||||
|
||||
```bash
|
||||
@@ -101,8 +101,8 @@ MG_CERTS_VAULT_HOST=http://vault:8200 \
|
||||
MG_CERTS_VAULT_NAMESPACE=magistrala \
|
||||
MG_CERTS_VAULT_APPROLE_ROLEID=magistrala \
|
||||
MG_CERTS_VAULT_APPROLE_SECRET=magistrala \
|
||||
MG_CERTS_VAULT_THINGS_CERTS_PKI_PATH=pki_int \
|
||||
MG_CERTS_VAULT_THINGS_CERTS_PKI_ROLE_NAME=magistrala_things_certs \
|
||||
MG_CERTS_VAULT_CLIENTS_CERTS_PKI_PATH=pki_int \
|
||||
MG_CERTS_VAULT_CLIENTS_CERTS_PKI_ROLE_NAME=magistrala_clients_certs \
|
||||
MG_CERTS_DB_HOST=localhost \
|
||||
MG_CERTS_DB_PORT=5432 \
|
||||
MG_CERTS_DB_PASS=magistrala \
|
||||
@@ -112,7 +112,7 @@ MG_CERTS_DB_SSL_MODE=disable \
|
||||
MG_CERTS_DB_SSL_CERT="" \
|
||||
MG_CERTS_DB_SSL_KEY="" \
|
||||
MG_CERTS_DB_SSL_ROOT_CERT="" \
|
||||
MG_THINGS_URL=localhost:9000 \
|
||||
MG_CLIENTS_URL=localhost:9000 \
|
||||
MG_JAEGER_URL=http://localhost:14268/api/traces \
|
||||
MG_JAEGER_TRACE_RATIO=1.0 \
|
||||
MG_SEND_TELEMETRY=true \
|
||||
|
||||
@@ -18,14 +18,14 @@ func issueCert(svc certs.Service) endpoint.Endpoint {
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
res, err := svc.IssueCert(ctx, req.domainID, req.token, req.ThingID, req.TTL)
|
||||
res, err := svc.IssueCert(ctx, req.domainID, req.token, req.ClientID, req.TTL)
|
||||
if err != nil {
|
||||
return certsRes{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
return certsRes{
|
||||
SerialNumber: res.SerialNumber,
|
||||
ThingID: res.ThingID,
|
||||
ClientID: res.ClientID,
|
||||
Certificate: res.Certificate,
|
||||
ExpiryTime: res.ExpiryTime,
|
||||
Revoked: res.Revoked,
|
||||
@@ -41,7 +41,7 @@ func listSerials(svc certs.Service) endpoint.Endpoint {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
page, err := svc.ListSerials(ctx, req.thingID, req.pm)
|
||||
page, err := svc.ListSerials(ctx, req.clientID, req.pm)
|
||||
if err != nil {
|
||||
return certsPageRes{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func listSerials(svc certs.Service) endpoint.Endpoint {
|
||||
SerialNumber: cert.SerialNumber,
|
||||
ExpiryTime: cert.ExpiryTime,
|
||||
Revoked: cert.Revoked,
|
||||
ThingID: cert.ThingID,
|
||||
ClientID: cert.ClientID,
|
||||
}
|
||||
res.Certs = append(res.Certs, cr)
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func viewCert(svc certs.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
return certsRes{
|
||||
ThingID: cert.ThingID,
|
||||
ClientID: cert.ClientID,
|
||||
Certificate: cert.Certificate,
|
||||
Key: cert.Key,
|
||||
SerialNumber: cert.SerialNumber,
|
||||
|
||||
+35
-35
@@ -31,11 +31,11 @@ var (
|
||||
contentType = "application/json"
|
||||
valid = "valid"
|
||||
invalid = "invalid"
|
||||
thingID = testsutil.GenerateUUID(&testing.T{})
|
||||
clientID = testsutil.GenerateUUID(&testing.T{})
|
||||
serial = testsutil.GenerateUUID(&testing.T{})
|
||||
ttl = "1h"
|
||||
cert = certs.Cert{
|
||||
ThingID: thingID,
|
||||
ClientID: clientID,
|
||||
SerialNumber: serial,
|
||||
ExpiryTime: time.Now().Add(time.Hour),
|
||||
}
|
||||
@@ -79,8 +79,8 @@ func TestIssueCert(t *testing.T) {
|
||||
cs, svc, auth := newCertServer()
|
||||
defer cs.Close()
|
||||
|
||||
validReqString := `{"thing_id": "%s","ttl": "%s"}`
|
||||
invalidReqString := `{"thing_id": "%s","ttl": %s}`
|
||||
validReqString := `{"client_id": "%s","ttl": "%s"}`
|
||||
invalidReqString := `{"client_id": "%s","ttl": %s}`
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -88,7 +88,7 @@ func TestIssueCert(t *testing.T) {
|
||||
token string
|
||||
session mgauthn.Session
|
||||
contentType string
|
||||
thingID string
|
||||
clientID string
|
||||
ttl string
|
||||
request string
|
||||
status int
|
||||
@@ -102,9 +102,9 @@ func TestIssueCert(t *testing.T) {
|
||||
token: valid,
|
||||
domainID: valid,
|
||||
contentType: contentType,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
ttl: ttl,
|
||||
request: fmt.Sprintf(validReqString, thingID, ttl),
|
||||
request: fmt.Sprintf(validReqString, clientID, ttl),
|
||||
status: http.StatusCreated,
|
||||
svcRes: certs.Cert{SerialNumber: serial},
|
||||
svcErr: nil,
|
||||
@@ -115,9 +115,9 @@ func TestIssueCert(t *testing.T) {
|
||||
token: valid,
|
||||
domainID: valid,
|
||||
contentType: contentType,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
ttl: ttl,
|
||||
request: fmt.Sprintf(validReqString, thingID, ttl),
|
||||
request: fmt.Sprintf(validReqString, clientID, ttl),
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcRes: certs.Cert{},
|
||||
svcErr: svcerr.ErrCreateEntity,
|
||||
@@ -127,9 +127,9 @@ func TestIssueCert(t *testing.T) {
|
||||
desc: "issue with invalid token",
|
||||
token: invalid,
|
||||
contentType: contentType,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
ttl: ttl,
|
||||
request: fmt.Sprintf(validReqString, thingID, ttl),
|
||||
request: fmt.Sprintf(validReqString, clientID, ttl),
|
||||
status: http.StatusUnauthorized,
|
||||
svcRes: certs.Cert{},
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
@@ -139,7 +139,7 @@ func TestIssueCert(t *testing.T) {
|
||||
desc: "issue with empty token",
|
||||
domainID: valid,
|
||||
contentType: contentType,
|
||||
request: fmt.Sprintf(validReqString, thingID, ttl),
|
||||
request: fmt.Sprintf(validReqString, clientID, ttl),
|
||||
status: http.StatusUnauthorized,
|
||||
svcRes: certs.Cert{},
|
||||
svcErr: nil,
|
||||
@@ -150,14 +150,14 @@ func TestIssueCert(t *testing.T) {
|
||||
token: valid,
|
||||
domainID: "",
|
||||
contentType: contentType,
|
||||
request: fmt.Sprintf(validReqString, thingID, ttl),
|
||||
request: fmt.Sprintf(validReqString, clientID, ttl),
|
||||
status: http.StatusBadRequest,
|
||||
svcRes: certs.Cert{},
|
||||
svcErr: nil,
|
||||
err: apiutil.ErrMissingDomainID,
|
||||
},
|
||||
{
|
||||
desc: "issue with empty thing id",
|
||||
desc: "issue with empty client id",
|
||||
token: valid,
|
||||
domainID: valid,
|
||||
contentType: contentType,
|
||||
@@ -172,7 +172,7 @@ func TestIssueCert(t *testing.T) {
|
||||
token: valid,
|
||||
domainID: valid,
|
||||
contentType: contentType,
|
||||
request: fmt.Sprintf(validReqString, thingID, ""),
|
||||
request: fmt.Sprintf(validReqString, clientID, ""),
|
||||
status: http.StatusBadRequest,
|
||||
svcRes: certs.Cert{},
|
||||
svcErr: nil,
|
||||
@@ -183,7 +183,7 @@ func TestIssueCert(t *testing.T) {
|
||||
token: valid,
|
||||
domainID: valid,
|
||||
contentType: contentType,
|
||||
request: fmt.Sprintf(validReqString, thingID, invalid),
|
||||
request: fmt.Sprintf(validReqString, clientID, invalid),
|
||||
status: http.StatusBadRequest,
|
||||
svcRes: certs.Cert{},
|
||||
svcErr: nil,
|
||||
@@ -194,7 +194,7 @@ func TestIssueCert(t *testing.T) {
|
||||
token: valid,
|
||||
domainID: valid,
|
||||
contentType: "application/xml",
|
||||
request: fmt.Sprintf(validReqString, thingID, ttl),
|
||||
request: fmt.Sprintf(validReqString, clientID, ttl),
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
svcRes: certs.Cert{},
|
||||
svcErr: nil,
|
||||
@@ -205,7 +205,7 @@ func TestIssueCert(t *testing.T) {
|
||||
token: valid,
|
||||
domainID: valid,
|
||||
contentType: contentType,
|
||||
request: fmt.Sprintf(invalidReqString, thingID, ttl),
|
||||
request: fmt.Sprintf(invalidReqString, clientID, ttl),
|
||||
status: http.StatusInternalServerError,
|
||||
svcRes: certs.Cert{},
|
||||
svcErr: nil,
|
||||
@@ -227,7 +227,7 @@ func TestIssueCert(t *testing.T) {
|
||||
tc.session = mgauthn.Session{DomainUserID: validID, UserID: validID, DomainID: validID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("IssueCert", mock.Anything, tc.domainID, tc.token, tc.thingID, tc.ttl).Return(tc.svcRes, tc.svcErr)
|
||||
svcCall := svc.On("IssueCert", mock.Anything, tc.domainID, tc.token, tc.clientID, tc.ttl).Return(tc.svcRes, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var errRes respBody
|
||||
@@ -433,7 +433,7 @@ func TestListSerials(t *testing.T) {
|
||||
token string
|
||||
domainID string
|
||||
session mgauthn.Session
|
||||
thingID string
|
||||
clientID string
|
||||
revoked string
|
||||
offset uint64
|
||||
limit uint64
|
||||
@@ -448,7 +448,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list certs successfully with default limit",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
@@ -467,7 +467,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list certs successfully with default revoke",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
@@ -486,7 +486,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list certs successfully with all certs",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: "all",
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
@@ -505,7 +505,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list certs successfully with limit",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
offset: 0,
|
||||
limit: 5,
|
||||
@@ -524,7 +524,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list certs successfully with offset",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
offset: 1,
|
||||
limit: 10,
|
||||
@@ -543,7 +543,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list certs successfully with offset and limit",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
offset: 1,
|
||||
limit: 5,
|
||||
@@ -562,7 +562,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list with invalid token",
|
||||
domainID: valid,
|
||||
token: invalid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
@@ -576,7 +576,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list with empty token",
|
||||
domainID: valid,
|
||||
token: "",
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
@@ -590,7 +590,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list with limit exceeding max limit",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
query: "?limit=1000",
|
||||
status: http.StatusBadRequest,
|
||||
@@ -602,7 +602,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list with invalid offset",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
query: "?offset=invalid",
|
||||
status: http.StatusBadRequest,
|
||||
@@ -614,7 +614,7 @@ func TestListSerials(t *testing.T) {
|
||||
desc: "list with invalid limit",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
revoked: revoked,
|
||||
query: "?limit=invalid",
|
||||
status: http.StatusBadRequest,
|
||||
@@ -623,10 +623,10 @@ func TestListSerials(t *testing.T) {
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "list with invalid thing id",
|
||||
desc: "list with invalid client id",
|
||||
domainID: valid,
|
||||
token: valid,
|
||||
thingID: invalid,
|
||||
clientID: invalid,
|
||||
revoked: revoked,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
@@ -642,14 +642,14 @@ func TestListSerials(t *testing.T) {
|
||||
req := testRequest{
|
||||
client: cs.Client(),
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/%s/serials/%s", cs.URL, tc.domainID, tc.thingID) + tc.query,
|
||||
url: fmt.Sprintf("%s/%s/serials/%s", cs.URL, tc.domainID, tc.clientID) + tc.query,
|
||||
token: tc.token,
|
||||
}
|
||||
if tc.token == valid {
|
||||
tc.session = mgauthn.Session{DomainUserID: validID, UserID: validID, DomainID: validID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("ListSerials", mock.Anything, tc.thingID, certs.PageMetadata{Revoked: tc.revoked, Offset: tc.offset, Limit: tc.limit}).Return(tc.svcRes, tc.svcErr)
|
||||
svcCall := svc.On("ListSerials", mock.Anything, tc.clientID, certs.PageMetadata{Revoked: tc.revoked, Offset: tc.offset, Limit: tc.limit}).Return(tc.svcRes, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var errRes respBody
|
||||
|
||||
+16
-16
@@ -25,13 +25,13 @@ func LoggingMiddleware(svc certs.Service, logger *slog.Logger) certs.Service {
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
// IssueCert logs the issue_cert request. It logs the ttl, thing ID and the time it took to complete the request.
|
||||
// IssueCert logs the issue_cert request. It logs the ttl, client ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) IssueCert(ctx context.Context, domainID, token, thingID, ttl string) (c certs.Cert, err error) {
|
||||
func (lm *loggingMiddleware) IssueCert(ctx context.Context, domainID, token, clientID, ttl string) (c certs.Cert, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", thingID),
|
||||
slog.String("client_id", clientID),
|
||||
slog.String("ttl", ttl),
|
||||
}
|
||||
if err != nil {
|
||||
@@ -42,15 +42,15 @@ func (lm *loggingMiddleware) IssueCert(ctx context.Context, domainID, token, thi
|
||||
lm.logger.Info("Issue certificate completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.IssueCert(ctx, domainID, token, thingID, ttl)
|
||||
return lm.svc.IssueCert(ctx, domainID, token, clientID, ttl)
|
||||
}
|
||||
|
||||
// ListCerts logs the list_certs request. It logs the thing ID and the time it took to complete the request.
|
||||
func (lm *loggingMiddleware) ListCerts(ctx context.Context, thingID string, pm certs.PageMetadata) (cp certs.CertPage, err error) {
|
||||
// ListCerts logs the list_certs request. It logs the client ID and the time it took to complete the request.
|
||||
func (lm *loggingMiddleware) ListCerts(ctx context.Context, clientID string, pm certs.PageMetadata) (cp certs.CertPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", thingID),
|
||||
slog.String("client_id", clientID),
|
||||
slog.Group("page",
|
||||
slog.Uint64("offset", cp.Offset),
|
||||
slog.Uint64("limit", cp.Limit),
|
||||
@@ -65,16 +65,16 @@ func (lm *loggingMiddleware) ListCerts(ctx context.Context, thingID string, pm c
|
||||
lm.logger.Info("List certificates completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.ListCerts(ctx, thingID, pm)
|
||||
return lm.svc.ListCerts(ctx, clientID, pm)
|
||||
}
|
||||
|
||||
// ListSerials logs the list_serials request. It logs the thing ID and the time it took to complete the request.
|
||||
// ListSerials logs the list_serials request. It logs the client ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) ListSerials(ctx context.Context, thingID string, pm certs.PageMetadata) (cp certs.CertPage, err error) {
|
||||
func (lm *loggingMiddleware) ListSerials(ctx context.Context, clientID string, pm certs.PageMetadata) (cp certs.CertPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", thingID),
|
||||
slog.String("client_id", clientID),
|
||||
slog.String("revoke", pm.Revoked),
|
||||
slog.Group("page",
|
||||
slog.Uint64("offset", cp.Offset),
|
||||
@@ -90,7 +90,7 @@ func (lm *loggingMiddleware) ListSerials(ctx context.Context, thingID string, pm
|
||||
lm.logger.Info("List certificates serials completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.ListSerials(ctx, thingID, pm)
|
||||
return lm.svc.ListSerials(ctx, clientID, pm)
|
||||
}
|
||||
|
||||
// ViewCert logs the view_cert request. It logs the serial ID and the time it took to complete the request.
|
||||
@@ -112,13 +112,13 @@ func (lm *loggingMiddleware) ViewCert(ctx context.Context, serialID string) (c c
|
||||
return lm.svc.ViewCert(ctx, serialID)
|
||||
}
|
||||
|
||||
// RevokeCert logs the revoke_cert request. It logs the thing ID and the time it took to complete the request.
|
||||
// RevokeCert logs the revoke_cert request. It logs the client ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) RevokeCert(ctx context.Context, domainID, token, thingID string) (c certs.Revoke, err error) {
|
||||
func (lm *loggingMiddleware) RevokeCert(ctx context.Context, domainID, token, clientID string) (c certs.Revoke, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("thing_id", thingID),
|
||||
slog.String("client_id", clientID),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.Any("error", err))
|
||||
@@ -128,5 +128,5 @@ func (lm *loggingMiddleware) RevokeCert(ctx context.Context, domainID, token, th
|
||||
lm.logger.Info("Revoke certificate completed successfully", args...)
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.RevokeCert(ctx, domainID, token, thingID)
|
||||
return lm.svc.RevokeCert(ctx, domainID, token, clientID)
|
||||
}
|
||||
|
||||
@@ -31,33 +31,33 @@ func MetricsMiddleware(svc certs.Service, counter metrics.Counter, latency metri
|
||||
}
|
||||
|
||||
// IssueCert instruments IssueCert method with metrics.
|
||||
func (ms *metricsMiddleware) IssueCert(ctx context.Context, domainID, token, thingID, ttl string) (certs.Cert, error) {
|
||||
func (ms *metricsMiddleware) IssueCert(ctx context.Context, domainID, token, clientID, ttl string) (certs.Cert, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "issue_cert").Add(1)
|
||||
ms.latency.With("method", "issue_cert").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.IssueCert(ctx, domainID, token, thingID, ttl)
|
||||
return ms.svc.IssueCert(ctx, domainID, token, clientID, ttl)
|
||||
}
|
||||
|
||||
// ListCerts instruments ListCerts method with metrics.
|
||||
func (ms *metricsMiddleware) ListCerts(ctx context.Context, thingID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
func (ms *metricsMiddleware) ListCerts(ctx context.Context, clientID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_certs").Add(1)
|
||||
ms.latency.With("method", "list_certs").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.ListCerts(ctx, thingID, pm)
|
||||
return ms.svc.ListCerts(ctx, clientID, pm)
|
||||
}
|
||||
|
||||
// ListSerials instruments ListSerials method with metrics.
|
||||
func (ms *metricsMiddleware) ListSerials(ctx context.Context, thingID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
func (ms *metricsMiddleware) ListSerials(ctx context.Context, clientID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_serials").Add(1)
|
||||
ms.latency.With("method", "list_serials").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.ListSerials(ctx, thingID, pm)
|
||||
return ms.svc.ListSerials(ctx, clientID, pm)
|
||||
}
|
||||
|
||||
// ViewCert instruments ViewCert method with metrics.
|
||||
@@ -71,11 +71,11 @@ func (ms *metricsMiddleware) ViewCert(ctx context.Context, serialID string) (cer
|
||||
}
|
||||
|
||||
// RevokeCert instruments RevokeCert method with metrics.
|
||||
func (ms *metricsMiddleware) RevokeCert(ctx context.Context, domainID, token, thingID string) (certs.Revoke, error) {
|
||||
func (ms *metricsMiddleware) RevokeCert(ctx context.Context, domainID, token, clientID string) (certs.Revoke, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "revoke_cert").Add(1)
|
||||
ms.latency.With("method", "revoke_cert").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.RevokeCert(ctx, domainID, token, thingID)
|
||||
return ms.svc.RevokeCert(ctx, domainID, token, clientID)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const maxLimitSize = 100
|
||||
type addCertsReq struct {
|
||||
token string
|
||||
domainID string
|
||||
ThingID string `json:"thing_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
TTL string `json:"ttl"`
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func (req addCertsReq) validate() error {
|
||||
return apiutil.ErrMissingDomainID
|
||||
}
|
||||
|
||||
if req.ThingID == "" {
|
||||
if req.ClientID == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ func (req addCertsReq) validate() error {
|
||||
}
|
||||
|
||||
type listReq struct {
|
||||
thingID string
|
||||
pm certs.PageMetadata
|
||||
clientID string
|
||||
pm certs.PageMetadata
|
||||
}
|
||||
|
||||
func (req *listReq) validate() error {
|
||||
|
||||
@@ -20,7 +20,7 @@ type certsPageRes struct {
|
||||
}
|
||||
|
||||
type certsRes struct {
|
||||
ThingID string `json:"thing_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
Certificate string `json:"certificate,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
SerialNumber string `json:"serial_number"`
|
||||
|
||||
@@ -62,7 +62,7 @@ func MakeHandler(svc certs.Service, authn mgauthn.Authentication, logger *slog.L
|
||||
opts...,
|
||||
), "revoke").ServeHTTP)
|
||||
})
|
||||
r.Get("/serials/{thingID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
r.Get("/serials/{clientID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listSerials(svc),
|
||||
decodeListCerts,
|
||||
api.EncodeResponse,
|
||||
@@ -91,7 +91,7 @@ func decodeListCerts(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
}
|
||||
|
||||
req := listReq{
|
||||
thingID: chi.URLParam(r, "thingID"),
|
||||
clientID: chi.URLParam(r, "clientID"),
|
||||
pm: certs.PageMetadata{
|
||||
Offset: o,
|
||||
Limit: l,
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ type Cert struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Revoked bool `json:"revoked"`
|
||||
ExpiryTime time.Time `json:"expiry_time"`
|
||||
ThingID string `json:"entity_id"`
|
||||
ClientID string `json:"entity_id"`
|
||||
}
|
||||
|
||||
type CertPage struct {
|
||||
@@ -33,7 +33,7 @@ type PageMetadata struct {
|
||||
Total uint64 `json:"total,omitempty"`
|
||||
Offset uint64 `json:"offset,omitempty"`
|
||||
Limit uint64 `json:"limit,omitempty"`
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
CommonName string `json:"common_name,omitempty"`
|
||||
Revoked string `json:"revoked,omitempty"`
|
||||
|
||||
+24
-24
@@ -17,9 +17,9 @@ type Service struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// IssueCert provides a mock function with given fields: ctx, domainID, token, thingID, ttl
|
||||
func (_m *Service) IssueCert(ctx context.Context, domainID string, token string, thingID string, ttl string) (certs.Cert, error) {
|
||||
ret := _m.Called(ctx, domainID, token, thingID, ttl)
|
||||
// IssueCert provides a mock function with given fields: ctx, domainID, token, clientID, ttl
|
||||
func (_m *Service) IssueCert(ctx context.Context, domainID string, token string, clientID string, ttl string) (certs.Cert, error) {
|
||||
ret := _m.Called(ctx, domainID, token, clientID, ttl)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for IssueCert")
|
||||
@@ -28,16 +28,16 @@ func (_m *Service) IssueCert(ctx context.Context, domainID string, token string,
|
||||
var r0 certs.Cert
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) (certs.Cert, error)); ok {
|
||||
return rf(ctx, domainID, token, thingID, ttl)
|
||||
return rf(ctx, domainID, token, clientID, ttl)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) certs.Cert); ok {
|
||||
r0 = rf(ctx, domainID, token, thingID, ttl)
|
||||
r0 = rf(ctx, domainID, token, clientID, ttl)
|
||||
} else {
|
||||
r0 = ret.Get(0).(certs.Cert)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) error); ok {
|
||||
r1 = rf(ctx, domainID, token, thingID, ttl)
|
||||
r1 = rf(ctx, domainID, token, clientID, ttl)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -45,9 +45,9 @@ func (_m *Service) IssueCert(ctx context.Context, domainID string, token string,
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListCerts provides a mock function with given fields: ctx, thingID, pm
|
||||
func (_m *Service) ListCerts(ctx context.Context, thingID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
ret := _m.Called(ctx, thingID, pm)
|
||||
// ListCerts provides a mock function with given fields: ctx, clientID, pm
|
||||
func (_m *Service) ListCerts(ctx context.Context, clientID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
ret := _m.Called(ctx, clientID, pm)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListCerts")
|
||||
@@ -56,16 +56,16 @@ func (_m *Service) ListCerts(ctx context.Context, thingID string, pm certs.PageM
|
||||
var r0 certs.CertPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, certs.PageMetadata) (certs.CertPage, error)); ok {
|
||||
return rf(ctx, thingID, pm)
|
||||
return rf(ctx, clientID, pm)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, certs.PageMetadata) certs.CertPage); ok {
|
||||
r0 = rf(ctx, thingID, pm)
|
||||
r0 = rf(ctx, clientID, pm)
|
||||
} else {
|
||||
r0 = ret.Get(0).(certs.CertPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, certs.PageMetadata) error); ok {
|
||||
r1 = rf(ctx, thingID, pm)
|
||||
r1 = rf(ctx, clientID, pm)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -73,9 +73,9 @@ func (_m *Service) ListCerts(ctx context.Context, thingID string, pm certs.PageM
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListSerials provides a mock function with given fields: ctx, thingID, pm
|
||||
func (_m *Service) ListSerials(ctx context.Context, thingID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
ret := _m.Called(ctx, thingID, pm)
|
||||
// ListSerials provides a mock function with given fields: ctx, clientID, pm
|
||||
func (_m *Service) ListSerials(ctx context.Context, clientID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
ret := _m.Called(ctx, clientID, pm)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListSerials")
|
||||
@@ -84,16 +84,16 @@ func (_m *Service) ListSerials(ctx context.Context, thingID string, pm certs.Pag
|
||||
var r0 certs.CertPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, certs.PageMetadata) (certs.CertPage, error)); ok {
|
||||
return rf(ctx, thingID, pm)
|
||||
return rf(ctx, clientID, pm)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, certs.PageMetadata) certs.CertPage); ok {
|
||||
r0 = rf(ctx, thingID, pm)
|
||||
r0 = rf(ctx, clientID, pm)
|
||||
} else {
|
||||
r0 = ret.Get(0).(certs.CertPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, certs.PageMetadata) error); ok {
|
||||
r1 = rf(ctx, thingID, pm)
|
||||
r1 = rf(ctx, clientID, pm)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -101,9 +101,9 @@ func (_m *Service) ListSerials(ctx context.Context, thingID string, pm certs.Pag
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RevokeCert provides a mock function with given fields: ctx, domainID, token, thingID
|
||||
func (_m *Service) RevokeCert(ctx context.Context, domainID string, token string, thingID string) (certs.Revoke, error) {
|
||||
ret := _m.Called(ctx, domainID, token, thingID)
|
||||
// RevokeCert provides a mock function with given fields: ctx, domainID, token, clientID
|
||||
func (_m *Service) RevokeCert(ctx context.Context, domainID string, token string, clientID string) (certs.Revoke, error) {
|
||||
ret := _m.Called(ctx, domainID, token, clientID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RevokeCert")
|
||||
@@ -112,16 +112,16 @@ func (_m *Service) RevokeCert(ctx context.Context, domainID string, token string
|
||||
var r0 certs.Revoke
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (certs.Revoke, error)); ok {
|
||||
return rf(ctx, domainID, token, thingID)
|
||||
return rf(ctx, domainID, token, clientID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) certs.Revoke); ok {
|
||||
r0 = rf(ctx, domainID, token, thingID)
|
||||
r0 = rf(ctx, domainID, token, clientID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(certs.Revoke)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {
|
||||
r1 = rf(ctx, domainID, token, thingID)
|
||||
r1 = rf(ctx, domainID, token, clientID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type Cert struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Revoked bool `json:"revoked"`
|
||||
ExpiryTime time.Time `json:"expiry_time"`
|
||||
ThingID string `json:"entity_id"`
|
||||
ClientID string `json:"entity_id"`
|
||||
DownloadUrl string `json:"-"`
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func (c sdkAgent) Issue(entityId, ttl string, ipAddrs []string) (Cert, error) {
|
||||
Certificate: cert.Certificate,
|
||||
Revoked: cert.Revoked,
|
||||
ExpiryTime: cert.ExpiryTime,
|
||||
ThingID: cert.EntityID,
|
||||
ClientID: cert.EntityID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func (c sdkAgent) View(serial string) (Cert, error) {
|
||||
Key: cert.Key,
|
||||
Revoked: cert.Revoked,
|
||||
ExpiryTime: cert.ExpiryTime,
|
||||
ThingID: cert.EntityID,
|
||||
ClientID: cert.EntityID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func (c sdkAgent) ListCerts(pm sdk.PageMetadata) (CertPage, error) {
|
||||
Key: c.Key,
|
||||
Revoked: c.Revoked,
|
||||
ExpiryTime: c.ExpiryTime,
|
||||
ThingID: c.EntityID,
|
||||
ClientID: c.EntityID,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+22
-22
@@ -33,20 +33,20 @@ var _ Service = (*certsService)(nil)
|
||||
//
|
||||
//go:generate mockery --name Service --output=./mocks --filename service.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type Service interface {
|
||||
// IssueCert issues certificate for given thing id if access is granted with token
|
||||
IssueCert(ctx context.Context, domainID, token, thingID, ttl string) (Cert, error)
|
||||
// IssueCert issues certificate for given client id if access is granted with token
|
||||
IssueCert(ctx context.Context, domainID, token, clientID, ttl string) (Cert, error)
|
||||
|
||||
// ListCerts lists certificates issued for a given thing ID
|
||||
ListCerts(ctx context.Context, thingID string, pm PageMetadata) (CertPage, error)
|
||||
// ListCerts lists certificates issued for a given client ID
|
||||
ListCerts(ctx context.Context, clientID string, pm PageMetadata) (CertPage, error)
|
||||
|
||||
// ListSerials lists certificate serial IDs issued for a given thing ID
|
||||
ListSerials(ctx context.Context, thingID string, pm PageMetadata) (CertPage, error)
|
||||
// ListSerials lists certificate serial IDs issued for a given client ID
|
||||
ListSerials(ctx context.Context, clientID string, pm PageMetadata) (CertPage, error)
|
||||
|
||||
// ViewCert retrieves the certificate issued for a given serial ID
|
||||
ViewCert(ctx context.Context, serialID string) (Cert, error)
|
||||
|
||||
// RevokeCert revokes a certificate for a given thing ID
|
||||
RevokeCert(ctx context.Context, domainID, token, thingID string) (Revoke, error)
|
||||
// RevokeCert revokes a certificate for a given client ID
|
||||
RevokeCert(ctx context.Context, domainID, token, clientID string) (Revoke, error)
|
||||
}
|
||||
|
||||
type certsService struct {
|
||||
@@ -67,15 +67,15 @@ type Revoke struct {
|
||||
RevocationTime time.Time `mapstructure:"revocation_time"`
|
||||
}
|
||||
|
||||
func (cs *certsService) IssueCert(ctx context.Context, domainID, token, thingID, ttl string) (Cert, error) {
|
||||
func (cs *certsService) IssueCert(ctx context.Context, domainID, token, clientID, ttl string) (Cert, error) {
|
||||
var err error
|
||||
|
||||
thing, err := cs.sdk.Thing(thingID, domainID, token)
|
||||
client, err := cs.sdk.Client(clientID, domainID, token)
|
||||
if err != nil {
|
||||
return Cert{}, errors.Wrap(ErrFailedCertCreation, err)
|
||||
}
|
||||
|
||||
cert, err := cs.pki.Issue(thing.ID, ttl, []string{})
|
||||
cert, err := cs.pki.Issue(client.ID, ttl, []string{})
|
||||
if err != nil {
|
||||
return Cert{}, errors.Wrap(ErrFailedCertCreation, err)
|
||||
}
|
||||
@@ -86,20 +86,20 @@ func (cs *certsService) IssueCert(ctx context.Context, domainID, token, thingID,
|
||||
Key: cert.Key,
|
||||
Revoked: cert.Revoked,
|
||||
ExpiryTime: cert.ExpiryTime,
|
||||
ThingID: cert.ThingID,
|
||||
ClientID: cert.ClientID,
|
||||
}, err
|
||||
}
|
||||
|
||||
func (cs *certsService) RevokeCert(ctx context.Context, domainID, token, thingID string) (Revoke, error) {
|
||||
func (cs *certsService) RevokeCert(ctx context.Context, domainID, token, clientID string) (Revoke, error) {
|
||||
var revoke Revoke
|
||||
var err error
|
||||
|
||||
thing, err := cs.sdk.Thing(thingID, domainID, token)
|
||||
client, err := cs.sdk.Client(clientID, domainID, token)
|
||||
if err != nil {
|
||||
return revoke, errors.Wrap(ErrFailedCertRevocation, err)
|
||||
}
|
||||
|
||||
cp, err := cs.pki.ListCerts(sdk.PageMetadata{Offset: 0, Limit: 10000, EntityID: thing.ID})
|
||||
cp, err := cs.pki.ListCerts(sdk.PageMetadata{Offset: 0, Limit: 10000, EntityID: client.ID})
|
||||
if err != nil {
|
||||
return revoke, errors.Wrap(ErrFailedCertRevocation, err)
|
||||
}
|
||||
@@ -115,8 +115,8 @@ func (cs *certsService) RevokeCert(ctx context.Context, domainID, token, thingID
|
||||
return revoke, nil
|
||||
}
|
||||
|
||||
func (cs *certsService) ListCerts(ctx context.Context, thingID string, pm PageMetadata) (CertPage, error) {
|
||||
cp, err := cs.pki.ListCerts(sdk.PageMetadata{Offset: pm.Offset, Limit: pm.Limit, EntityID: thingID})
|
||||
func (cs *certsService) ListCerts(ctx context.Context, clientID string, pm PageMetadata) (CertPage, error) {
|
||||
cp, err := cs.pki.ListCerts(sdk.PageMetadata{Offset: pm.Offset, Limit: pm.Limit, EntityID: clientID})
|
||||
if err != nil {
|
||||
return CertPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func (cs *certsService) ListCerts(ctx context.Context, thingID string, pm PageMe
|
||||
Key: c.Key,
|
||||
Revoked: c.Revoked,
|
||||
ExpiryTime: c.ExpiryTime,
|
||||
ThingID: c.ThingID,
|
||||
ClientID: c.ClientID,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -142,8 +142,8 @@ func (cs *certsService) ListCerts(ctx context.Context, thingID string, pm PageMe
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cs *certsService) ListSerials(ctx context.Context, thingID string, pm PageMetadata) (CertPage, error) {
|
||||
cp, err := cs.pki.ListCerts(sdk.PageMetadata{Offset: pm.Offset, Limit: pm.Limit, EntityID: thingID})
|
||||
func (cs *certsService) ListSerials(ctx context.Context, clientID string, pm PageMetadata) (CertPage, error) {
|
||||
cp, err := cs.pki.ListCerts(sdk.PageMetadata{Offset: pm.Offset, Limit: pm.Limit, EntityID: clientID})
|
||||
if err != nil {
|
||||
return CertPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
@@ -153,7 +153,7 @@ func (cs *certsService) ListSerials(ctx context.Context, thingID string, pm Page
|
||||
if (pm.Revoked == "true" && c.Revoked) || (pm.Revoked == "false" && !c.Revoked) || (pm.Revoked == "all") {
|
||||
certs = append(certs, Cert{
|
||||
SerialNumber: c.SerialNumber,
|
||||
ThingID: c.ThingID,
|
||||
ClientID: c.ClientID,
|
||||
ExpiryTime: c.ExpiryTime,
|
||||
Revoked: c.Revoked,
|
||||
})
|
||||
@@ -180,6 +180,6 @@ func (cs *certsService) ViewCert(ctx context.Context, serialID string) (Cert, er
|
||||
Key: cert.Key,
|
||||
Revoked: cert.Revoked,
|
||||
ExpiryTime: cert.ExpiryTime,
|
||||
ThingID: cert.ThingID,
|
||||
ClientID: cert.ClientID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
+106
-106
@@ -21,16 +21,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
invalid = "invalid"
|
||||
email = "user@example.com"
|
||||
domain = "domain"
|
||||
token = "token"
|
||||
thingsNum = 1
|
||||
thingKey = "thingKey"
|
||||
thingID = "1"
|
||||
ttl = "1h"
|
||||
certNum = 10
|
||||
validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22"
|
||||
invalid = "invalid"
|
||||
email = "user@example.com"
|
||||
domain = "domain"
|
||||
token = "token"
|
||||
clientsNum = 1
|
||||
clientKey = "clientKey"
|
||||
clientID = "1"
|
||||
ttl = "1h"
|
||||
certNum = 10
|
||||
validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22"
|
||||
)
|
||||
|
||||
func newService(_ *testing.T) (certs.Service, *mocks.Agent, *sdkmocks.SDK) {
|
||||
@@ -41,7 +41,7 @@ func newService(_ *testing.T) (certs.Service, *mocks.Agent, *sdkmocks.SDK) {
|
||||
}
|
||||
|
||||
var cert = mgcrt.Cert{
|
||||
ThingID: thingID,
|
||||
ClientID: clientID,
|
||||
SerialNumber: "Serial",
|
||||
ExpiryTime: time.Now().Add(time.Duration(1000)),
|
||||
Revoked: false,
|
||||
@@ -53,12 +53,12 @@ func TestIssueCert(t *testing.T) {
|
||||
domainID string
|
||||
token string
|
||||
desc string
|
||||
thingID string
|
||||
clientID string
|
||||
ttl string
|
||||
ipAddr []string
|
||||
key string
|
||||
cert mgcrt.Cert
|
||||
thingErr errors.SDKError
|
||||
clientErr errors.SDKError
|
||||
issueCertErr error
|
||||
err error
|
||||
}{
|
||||
@@ -66,7 +66,7 @@ func TestIssueCert(t *testing.T) {
|
||||
desc: "issue new cert",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
ttl: ttl,
|
||||
ipAddr: []string{},
|
||||
cert: cert,
|
||||
@@ -75,40 +75,40 @@ func TestIssueCert(t *testing.T) {
|
||||
desc: "issue new for failed pki",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
ttl: ttl,
|
||||
ipAddr: []string{},
|
||||
thingErr: nil,
|
||||
clientErr: nil,
|
||||
issueCertErr: certs.ErrFailedCertCreation,
|
||||
err: certs.ErrFailedCertCreation,
|
||||
},
|
||||
{
|
||||
desc: "issue new cert for non existing thing id",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
thingID: "2",
|
||||
ttl: ttl,
|
||||
ipAddr: []string{},
|
||||
thingErr: errors.NewSDKError(errors.ErrMalformedEntity),
|
||||
err: certs.ErrFailedCertCreation,
|
||||
desc: "issue new cert for non existing client id",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
clientID: "2",
|
||||
ttl: ttl,
|
||||
ipAddr: []string{},
|
||||
clientErr: errors.NewSDKError(errors.ErrMalformedEntity),
|
||||
err: certs.ErrFailedCertCreation,
|
||||
},
|
||||
{
|
||||
desc: "issue new cert for invalid token",
|
||||
domainID: domain,
|
||||
token: invalid,
|
||||
thingID: thingID,
|
||||
ttl: ttl,
|
||||
ipAddr: []string{},
|
||||
thingErr: errors.NewSDKError(svcerr.ErrAuthentication),
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "issue new cert for invalid token",
|
||||
domainID: domain,
|
||||
token: invalid,
|
||||
clientID: clientID,
|
||||
ttl: ttl,
|
||||
ipAddr: []string{},
|
||||
clientErr: errors.NewSDKError(svcerr.ErrAuthentication),
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdk.On("Thing", tc.thingID, tc.domainID, tc.token).Return(mgsdk.Thing{ID: tc.thingID, Credentials: mgsdk.ClientCredentials{Secret: thingKey}}, tc.thingErr)
|
||||
agentCall := agent.On("Issue", thingID, tc.ttl, tc.ipAddr).Return(tc.cert, tc.issueCertErr)
|
||||
resp, err := svc.IssueCert(context.Background(), tc.domainID, tc.token, tc.thingID, tc.ttl)
|
||||
sdkCall := sdk.On("Client", tc.clientID, tc.domainID, tc.token).Return(mgsdk.Client{ID: tc.clientID, Credentials: mgsdk.ClientCredentials{Secret: clientKey}}, tc.clientErr)
|
||||
agentCall := agent.On("Issue", clientID, tc.ttl, tc.ipAddr).Return(tc.cert, tc.issueCertErr)
|
||||
resp, err := svc.IssueCert(context.Background(), tc.domainID, tc.token, tc.clientID, tc.ttl)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.cert.SerialNumber, resp.SerialNumber, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.cert.SerialNumber, resp.SerialNumber))
|
||||
sdkCall.Unset()
|
||||
@@ -123,10 +123,10 @@ func TestRevokeCert(t *testing.T) {
|
||||
domainID string
|
||||
token string
|
||||
desc string
|
||||
thingID string
|
||||
clientID string
|
||||
page mgcrt.CertPage
|
||||
authErr error
|
||||
thingErr errors.SDKError
|
||||
clientErr errors.SDKError
|
||||
revokeErr error
|
||||
listErr error
|
||||
err error
|
||||
@@ -135,32 +135,32 @@ func TestRevokeCert(t *testing.T) {
|
||||
desc: "revoke cert",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
page: mgcrt.CertPage{Limit: 10000, Offset: 0, Total: 1, Certificates: []mgcrt.Cert{cert}},
|
||||
},
|
||||
{
|
||||
desc: "revoke cert for failed pki revoke",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
page: mgcrt.CertPage{Limit: 10000, Offset: 0, Total: 1, Certificates: []mgcrt.Cert{cert}},
|
||||
revokeErr: certs.ErrFailedCertRevocation,
|
||||
err: certs.ErrFailedCertRevocation,
|
||||
},
|
||||
{
|
||||
desc: "revoke cert for invalid thing id",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
thingID: "2",
|
||||
page: mgcrt.CertPage{},
|
||||
thingErr: errors.NewSDKError(certs.ErrFailedCertCreation),
|
||||
err: certs.ErrFailedCertRevocation,
|
||||
desc: "revoke cert for invalid client id",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
clientID: "2",
|
||||
page: mgcrt.CertPage{},
|
||||
clientErr: errors.NewSDKError(certs.ErrFailedCertCreation),
|
||||
err: certs.ErrFailedCertRevocation,
|
||||
},
|
||||
{
|
||||
desc: "revoke cert with failed to list certs",
|
||||
domainID: domain,
|
||||
token: token,
|
||||
thingID: thingID,
|
||||
clientID: clientID,
|
||||
page: mgcrt.CertPage{},
|
||||
listErr: certs.ErrFailedCertRevocation,
|
||||
err: certs.ErrFailedCertRevocation,
|
||||
@@ -169,10 +169,10 @@ func TestRevokeCert(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdk.On("Thing", tc.thingID, tc.domainID, tc.token).Return(mgsdk.Thing{ID: tc.thingID, Credentials: mgsdk.ClientCredentials{Secret: thingKey}}, tc.thingErr)
|
||||
sdkCall := sdk.On("Client", tc.clientID, tc.domainID, tc.token).Return(mgsdk.Client{ID: tc.clientID, Credentials: mgsdk.ClientCredentials{Secret: clientKey}}, tc.clientErr)
|
||||
agentCall := agent.On("Revoke", mock.Anything).Return(tc.revokeErr)
|
||||
agentCall1 := agent.On("ListCerts", mock.Anything).Return(tc.page, tc.listErr)
|
||||
_, err := svc.RevokeCert(context.Background(), tc.domainID, tc.token, tc.thingID)
|
||||
_, err := svc.RevokeCert(context.Background(), tc.domainID, tc.token, tc.clientID)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
sdkCall.Unset()
|
||||
agentCall.Unset()
|
||||
@@ -186,7 +186,7 @@ func TestListCerts(t *testing.T) {
|
||||
var mycerts []mgcrt.Cert
|
||||
for i := 0; i < certNum; i++ {
|
||||
c := mgcrt.Cert{
|
||||
ThingID: thingID,
|
||||
ClientID: clientID,
|
||||
SerialNumber: fmt.Sprintf("%d", i),
|
||||
ExpiryTime: time.Now().Add(time.Hour),
|
||||
}
|
||||
@@ -194,40 +194,40 @@ func TestListCerts(t *testing.T) {
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
page mgcrt.CertPage
|
||||
listErr error
|
||||
err error
|
||||
desc string
|
||||
clientID string
|
||||
page mgcrt.CertPage
|
||||
listErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "list all certs successfully",
|
||||
thingID: thingID,
|
||||
page: mgcrt.CertPage{Limit: certNum, Offset: 0, Total: certNum, Certificates: mycerts},
|
||||
desc: "list all certs successfully",
|
||||
clientID: clientID,
|
||||
page: mgcrt.CertPage{Limit: certNum, Offset: 0, Total: certNum, Certificates: mycerts},
|
||||
},
|
||||
{
|
||||
desc: "list all certs with failed pki",
|
||||
thingID: thingID,
|
||||
page: mgcrt.CertPage{},
|
||||
listErr: svcerr.ErrViewEntity,
|
||||
err: svcerr.ErrViewEntity,
|
||||
desc: "list all certs with failed pki",
|
||||
clientID: clientID,
|
||||
page: mgcrt.CertPage{},
|
||||
listErr: svcerr.ErrViewEntity,
|
||||
err: svcerr.ErrViewEntity,
|
||||
},
|
||||
{
|
||||
desc: "list half certs successfully",
|
||||
thingID: thingID,
|
||||
page: mgcrt.CertPage{Limit: certNum, Offset: certNum / 2, Total: certNum / 2, Certificates: mycerts[certNum/2:]},
|
||||
desc: "list half certs successfully",
|
||||
clientID: clientID,
|
||||
page: mgcrt.CertPage{Limit: certNum, Offset: certNum / 2, Total: certNum / 2, Certificates: mycerts[certNum/2:]},
|
||||
},
|
||||
{
|
||||
desc: "list last cert successfully",
|
||||
thingID: thingID,
|
||||
page: mgcrt.CertPage{Limit: certNum, Offset: certNum - 1, Total: 1, Certificates: []mgcrt.Cert{mycerts[certNum-1]}},
|
||||
desc: "list last cert successfully",
|
||||
clientID: clientID,
|
||||
page: mgcrt.CertPage{Limit: certNum, Offset: certNum - 1, Total: 1, Certificates: []mgcrt.Cert{mycerts[certNum-1]}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
agentCall := agent.On("ListCerts", mock.Anything).Return(tc.page, tc.listErr)
|
||||
page, err := svc.ListCerts(context.Background(), tc.thingID, certs.PageMetadata{Offset: tc.page.Offset, Limit: tc.page.Limit})
|
||||
page, err := svc.ListCerts(context.Background(), tc.clientID, certs.PageMetadata{Offset: tc.page.Offset, Limit: tc.page.Limit})
|
||||
size := uint64(len(page.Certificates))
|
||||
assert.Equal(t, tc.page.Total, size, fmt.Sprintf("%s: expected %d got %d\n", tc.desc, tc.page.Total, size))
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
@@ -243,7 +243,7 @@ func TestListSerials(t *testing.T) {
|
||||
var issuedCerts []mgcrt.Cert
|
||||
for i := 0; i < certNum; i++ {
|
||||
crt := mgcrt.Cert{
|
||||
ThingID: cert.ThingID,
|
||||
ClientID: cert.ClientID,
|
||||
SerialNumber: cert.SerialNumber,
|
||||
ExpiryTime: cert.ExpiryTime,
|
||||
Revoked: false,
|
||||
@@ -252,55 +252,55 @@ func TestListSerials(t *testing.T) {
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
revoke string
|
||||
offset uint64
|
||||
limit uint64
|
||||
certs []mgcrt.Cert
|
||||
listErr error
|
||||
err error
|
||||
desc string
|
||||
clientID string
|
||||
revoke string
|
||||
offset uint64
|
||||
limit uint64
|
||||
certs []mgcrt.Cert
|
||||
listErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "list all certs successfully",
|
||||
thingID: thingID,
|
||||
revoke: revoke,
|
||||
offset: 0,
|
||||
limit: certNum,
|
||||
certs: issuedCerts,
|
||||
desc: "list all certs successfully",
|
||||
clientID: clientID,
|
||||
revoke: revoke,
|
||||
offset: 0,
|
||||
limit: certNum,
|
||||
certs: issuedCerts,
|
||||
},
|
||||
{
|
||||
desc: "list all certs with failed pki",
|
||||
thingID: thingID,
|
||||
revoke: revoke,
|
||||
offset: 0,
|
||||
limit: certNum,
|
||||
certs: nil,
|
||||
listErr: svcerr.ErrViewEntity,
|
||||
err: svcerr.ErrViewEntity,
|
||||
desc: "list all certs with failed pki",
|
||||
clientID: clientID,
|
||||
revoke: revoke,
|
||||
offset: 0,
|
||||
limit: certNum,
|
||||
certs: nil,
|
||||
listErr: svcerr.ErrViewEntity,
|
||||
err: svcerr.ErrViewEntity,
|
||||
},
|
||||
{
|
||||
desc: "list half certs successfully",
|
||||
thingID: thingID,
|
||||
revoke: revoke,
|
||||
offset: certNum / 2,
|
||||
limit: certNum,
|
||||
certs: issuedCerts[certNum/2:],
|
||||
desc: "list half certs successfully",
|
||||
clientID: clientID,
|
||||
revoke: revoke,
|
||||
offset: certNum / 2,
|
||||
limit: certNum,
|
||||
certs: issuedCerts[certNum/2:],
|
||||
},
|
||||
{
|
||||
desc: "list last cert successfully",
|
||||
thingID: thingID,
|
||||
revoke: revoke,
|
||||
offset: certNum - 1,
|
||||
limit: certNum,
|
||||
certs: []mgcrt.Cert{issuedCerts[certNum-1]},
|
||||
desc: "list last cert successfully",
|
||||
clientID: clientID,
|
||||
revoke: revoke,
|
||||
offset: certNum - 1,
|
||||
limit: certNum,
|
||||
certs: []mgcrt.Cert{issuedCerts[certNum-1]},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
agentCall := agent.On("ListCerts", mock.Anything).Return(mgcrt.CertPage{Certificates: tc.certs}, tc.listErr)
|
||||
page, err := svc.ListSerials(context.Background(), tc.thingID, certs.PageMetadata{Revoked: tc.revoke, Offset: tc.offset, Limit: tc.limit})
|
||||
page, err := svc.ListSerials(context.Background(), tc.clientID, certs.PageMetadata{Revoked: tc.revoke, Offset: tc.offset, Limit: tc.limit})
|
||||
assert.Equal(t, len(tc.certs), len(page.Certificates), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.certs, page.Certificates))
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
agentCall.Unset()
|
||||
|
||||
@@ -24,38 +24,38 @@ func New(svc certs.Service, tracer trace.Tracer) certs.Service {
|
||||
}
|
||||
|
||||
// IssueCert traces the "IssueCert" operation of the wrapped certs.Service.
|
||||
func (tm *tracingMiddleware) IssueCert(ctx context.Context, domainID, token, thingID, ttl string) (certs.Cert, error) {
|
||||
func (tm *tracingMiddleware) IssueCert(ctx context.Context, domainID, token, clientID, ttl string) (certs.Cert, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_create_group", trace.WithAttributes(
|
||||
attribute.String("thing_id", thingID),
|
||||
attribute.String("client_id", clientID),
|
||||
attribute.String("ttl", ttl),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.IssueCert(ctx, domainID, token, thingID, ttl)
|
||||
return tm.svc.IssueCert(ctx, domainID, token, clientID, ttl)
|
||||
}
|
||||
|
||||
// ListCerts traces the "ListCerts" operation of the wrapped certs.Service.
|
||||
func (tm *tracingMiddleware) ListCerts(ctx context.Context, thingID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
func (tm *tracingMiddleware) ListCerts(ctx context.Context, clientID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_list_certs", trace.WithAttributes(
|
||||
attribute.String("thing_id", thingID),
|
||||
attribute.String("client_id", clientID),
|
||||
attribute.Int64("offset", int64(pm.Offset)),
|
||||
attribute.Int64("limit", int64(pm.Limit)),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.ListCerts(ctx, thingID, pm)
|
||||
return tm.svc.ListCerts(ctx, clientID, pm)
|
||||
}
|
||||
|
||||
// ListSerials traces the "ListSerials" operation of the wrapped certs.Service.
|
||||
func (tm *tracingMiddleware) ListSerials(ctx context.Context, thingID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
func (tm *tracingMiddleware) ListSerials(ctx context.Context, clientID string, pm certs.PageMetadata) (certs.CertPage, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_list_serials", trace.WithAttributes(
|
||||
attribute.String("thing_id", thingID),
|
||||
attribute.String("client_id", clientID),
|
||||
attribute.Int64("offset", int64(pm.Offset)),
|
||||
attribute.Int64("limit", int64(pm.Limit)),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.ListSerials(ctx, thingID, pm)
|
||||
return tm.svc.ListSerials(ctx, clientID, pm)
|
||||
}
|
||||
|
||||
// ViewCert traces the "ViewCert" operation of the wrapped certs.Service.
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
grpcChannelsV1 "github.com/absmach/magistrala/internal/grpc/channels/v1"
|
||||
grpcCommonV1 "github.com/absmach/magistrala/internal/grpc/common/v1"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const svcName = "channels.v1.ChannelsService"
|
||||
|
||||
var _ grpcChannelsV1.ChannelsServiceClient = (*grpcClient)(nil)
|
||||
|
||||
type grpcClient struct {
|
||||
timeout time.Duration
|
||||
authorize endpoint.Endpoint
|
||||
removeClientConnections endpoint.Endpoint
|
||||
unsetParentGroupFromChannels endpoint.Endpoint
|
||||
retrieveEntity endpoint.Endpoint
|
||||
}
|
||||
|
||||
// NewClient returns new gRPC client instance.
|
||||
func NewClient(conn *grpc.ClientConn, timeout time.Duration) grpcChannelsV1.ChannelsServiceClient {
|
||||
return &grpcClient{
|
||||
authorize: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"Authorize",
|
||||
encodeAuthorizeRequest,
|
||||
decodeAuthorizeResponse,
|
||||
grpcChannelsV1.AuthzRes{},
|
||||
).Endpoint(),
|
||||
removeClientConnections: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"RemoveClientConnections",
|
||||
encodeRemoveClientConnectionsRequest,
|
||||
decodeRemoveClientConnectionsResponse,
|
||||
grpcChannelsV1.RemoveClientConnectionsRes{},
|
||||
).Endpoint(),
|
||||
unsetParentGroupFromChannels: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"UnsetParentGroupFromChannels",
|
||||
encodeUnsetParentGroupFromChannelsRequest,
|
||||
decodeUnsetParentGroupFromChannelsResponse,
|
||||
grpcChannelsV1.UnsetParentGroupFromChannelsRes{},
|
||||
).Endpoint(),
|
||||
retrieveEntity: kitgrpc.NewClient(
|
||||
conn,
|
||||
svcName,
|
||||
"RetrieveEntity",
|
||||
encodeRetrieveEntityRequest,
|
||||
decodeRetrieveEntityResponse,
|
||||
grpcCommonV1.RetrieveEntityRes{},
|
||||
).Endpoint(),
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func (client grpcClient) Authorize(ctx context.Context, req *grpcChannelsV1.AuthzReq, _ ...grpc.CallOption) (r *grpcChannelsV1.AuthzRes, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.authorize(ctx, authorizeReq{
|
||||
domainID: req.GetDomainId(),
|
||||
clientID: req.GetClientId(),
|
||||
clientType: req.GetClientType(),
|
||||
channelID: req.GetChannelId(),
|
||||
connType: connections.ConnType(req.GetType()),
|
||||
})
|
||||
if err != nil {
|
||||
return &grpcChannelsV1.AuthzRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
ar := res.(authorizeRes)
|
||||
|
||||
return &grpcChannelsV1.AuthzRes{Authorized: ar.authorized}, nil
|
||||
}
|
||||
|
||||
func encodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(authorizeReq)
|
||||
|
||||
return &grpcChannelsV1.AuthzReq{
|
||||
DomainId: req.domainID,
|
||||
ClientId: req.clientID,
|
||||
ClientType: req.clientType,
|
||||
ChannelId: req.channelID,
|
||||
Type: uint32(req.connType),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(*grpcChannelsV1.AuthzRes)
|
||||
|
||||
return authorizeRes{authorized: res.GetAuthorized()}, nil
|
||||
}
|
||||
|
||||
func (client grpcClient) RemoveClientConnections(ctx context.Context, req *grpcChannelsV1.RemoveClientConnectionsReq, _ ...grpc.CallOption) (r *grpcChannelsV1.RemoveClientConnectionsRes, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
if _, err := client.removeClientConnections(ctx, req); err != nil {
|
||||
return &grpcChannelsV1.RemoveClientConnectionsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
return &grpcChannelsV1.RemoveClientConnectionsRes{}, nil
|
||||
}
|
||||
|
||||
func encodeRemoveClientConnectionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
return grpcReq.(*grpcChannelsV1.RemoveClientConnectionsReq), nil
|
||||
}
|
||||
|
||||
func decodeRemoveClientConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
return grpcRes.(*grpcChannelsV1.RemoveClientConnectionsRes), nil
|
||||
}
|
||||
|
||||
func (client grpcClient) UnsetParentGroupFromChannels(ctx context.Context, req *grpcChannelsV1.UnsetParentGroupFromChannelsReq, _ ...grpc.CallOption) (r *grpcChannelsV1.UnsetParentGroupFromChannelsRes, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
if _, err := client.unsetParentGroupFromChannels(ctx, req); err != nil {
|
||||
return &grpcChannelsV1.UnsetParentGroupFromChannelsRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
return &grpcChannelsV1.UnsetParentGroupFromChannelsRes{}, nil
|
||||
}
|
||||
|
||||
func encodeUnsetParentGroupFromChannelsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
return grpcReq.(*grpcChannelsV1.UnsetParentGroupFromChannelsReq), nil
|
||||
}
|
||||
|
||||
func decodeUnsetParentGroupFromChannelsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
return grpcRes.(*grpcChannelsV1.UnsetParentGroupFromChannelsRes), nil
|
||||
}
|
||||
|
||||
func (client grpcClient) RetrieveEntity(ctx context.Context, req *grpcCommonV1.RetrieveEntityReq, _ ...grpc.CallOption) (r *grpcCommonV1.RetrieveEntityRes, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, client.timeout)
|
||||
defer cancel()
|
||||
|
||||
res, err := client.retrieveEntity(ctx, req)
|
||||
if err != nil {
|
||||
return &grpcCommonV1.RetrieveEntityRes{}, decodeError(err)
|
||||
}
|
||||
|
||||
return res.(*grpcCommonV1.RetrieveEntityRes), nil
|
||||
}
|
||||
|
||||
func encodeRetrieveEntityRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
return grpcReq.(*grpcCommonV1.RetrieveEntityReq), nil
|
||||
}
|
||||
|
||||
func decodeRetrieveEntityResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
return grpcRes.(*grpcCommonV1.RetrieveEntityRes), nil
|
||||
}
|
||||
|
||||
func decodeError(err error) error {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
switch st.Code() {
|
||||
case codes.Unauthenticated:
|
||||
return errors.Wrap(svcerr.ErrAuthentication, errors.New(st.Message()))
|
||||
case codes.PermissionDenied:
|
||||
return errors.Wrap(svcerr.ErrAuthorization, errors.New(st.Message()))
|
||||
case codes.InvalidArgument:
|
||||
return errors.Wrap(errors.ErrMalformedEntity, errors.New(st.Message()))
|
||||
case codes.FailedPrecondition:
|
||||
return errors.Wrap(errors.ErrMalformedEntity, errors.New(st.Message()))
|
||||
case codes.NotFound:
|
||||
return errors.Wrap(svcerr.ErrNotFound, errors.New(st.Message()))
|
||||
case codes.AlreadyExists:
|
||||
return errors.Wrap(svcerr.ErrConflict, errors.New(st.Message()))
|
||||
case codes.OK:
|
||||
if msg := st.Message(); msg != "" {
|
||||
return errors.Wrap(errors.ErrUnidentified, errors.New(msg))
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return errors.Wrap(fmt.Errorf("unexpected gRPC status: %s (status code:%v)", st.Code().String(), st.Code()), errors.New(st.Message()))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ch "github.com/absmach/magistrala/channels"
|
||||
channels "github.com/absmach/magistrala/channels/private"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
func authorizeEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(authorizeReq)
|
||||
|
||||
if err := svc.Authorize(ctx, ch.AuthzReq{
|
||||
DomainID: req.domainID,
|
||||
ClientID: req.clientID,
|
||||
ClientType: req.clientType,
|
||||
ChannelID: req.channelID,
|
||||
Type: req.connType,
|
||||
}); err != nil {
|
||||
return authorizeRes{}, err
|
||||
}
|
||||
|
||||
return authorizeRes{authorized: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func removeClientConnectionsEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(removeClientConnectionsReq)
|
||||
|
||||
if err := svc.RemoveClientConnections(ctx, req.clientID); err != nil {
|
||||
return removeClientConnectionsRes{}, err
|
||||
}
|
||||
|
||||
return removeClientConnectionsRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func unsetParentGroupFromChannelsEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(unsetParentGroupFromChannelsReq)
|
||||
|
||||
if err := svc.UnsetParentGroupFromChannels(ctx, req.parentGroupID); err != nil {
|
||||
return unsetParentGroupFromChannelsRes{}, err
|
||||
}
|
||||
|
||||
return unsetParentGroupFromChannelsRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveEntityEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(retrieveEntityReq)
|
||||
channel, err := svc.RetrieveByID(ctx, req.Id)
|
||||
if err != nil {
|
||||
return retrieveEntityRes{}, err
|
||||
}
|
||||
|
||||
return retrieveEntityRes{id: channel.ID, domain: channel.Domain, parentGroup: channel.ParentGroup, status: uint8(channel.Status)}, nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ch "github.com/absmach/magistrala/channels"
|
||||
grpcapi "github.com/absmach/magistrala/channels/api/grpc"
|
||||
"github.com/absmach/magistrala/channels/private/mocks"
|
||||
"github.com/absmach/magistrala/clients"
|
||||
grpcChannelsV1 "github.com/absmach/magistrala/internal/grpc/channels/v1"
|
||||
grpcCommonV1 "github.com/absmach/magistrala/internal/grpc/common/v1"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/absmach/magistrala/pkg/policies"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
const port = 7005
|
||||
|
||||
var (
|
||||
validID = testsutil.GenerateUUID(&testing.T{})
|
||||
validChannel = ch.Channel{
|
||||
ID: validID,
|
||||
Domain: testsutil.GenerateUUID(&testing.T{}),
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
)
|
||||
|
||||
func startGRPCServer(svc *mocks.Service, port int) *grpc.Server {
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to obtain port: %s", err))
|
||||
}
|
||||
server := grpc.NewServer()
|
||||
grpcChannelsV1.RegisterChannelsServiceServer(server, grpcapi.NewServer(svc))
|
||||
go func() {
|
||||
if err := server.Serve(listener); err != nil {
|
||||
panic(fmt.Sprintf("failed to serve: %s", err))
|
||||
}
|
||||
}()
|
||||
return server
|
||||
}
|
||||
|
||||
func TestAuthorize(t *testing.T) {
|
||||
svc := new(mocks.Service)
|
||||
server := startGRPCServer(svc, port)
|
||||
defer server.GracefulStop()
|
||||
authAddr := fmt.Sprintf("localhost:%d", port)
|
||||
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
client := grpcapi.NewClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
domainID string
|
||||
clientID string
|
||||
clientType string
|
||||
channelID string
|
||||
connType connections.ConnType
|
||||
err error
|
||||
authzErr error
|
||||
res *grpcChannelsV1.AuthzRes
|
||||
code codes.Code
|
||||
}{
|
||||
{
|
||||
desc: "authorize successfully",
|
||||
domainID: validID,
|
||||
clientID: validID,
|
||||
clientType: policies.UserType,
|
||||
channelID: validID,
|
||||
connType: connections.Publish,
|
||||
res: &grpcChannelsV1.AuthzRes{Authorized: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authorize with authorization error",
|
||||
domainID: validID,
|
||||
clientID: validID,
|
||||
clientType: policies.UserType,
|
||||
channelID: validID,
|
||||
connType: connections.Publish,
|
||||
res: &grpcChannelsV1.AuthzRes{Authorized: false},
|
||||
authzErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "authorize withnot found error",
|
||||
domainID: validID,
|
||||
clientID: validID,
|
||||
clientType: policies.UserType,
|
||||
channelID: validID,
|
||||
connType: connections.Publish,
|
||||
res: &grpcChannelsV1.AuthzRes{Authorized: false},
|
||||
authzErr: svcerr.ErrNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
authReq := ch.AuthzReq{
|
||||
DomainID: tc.domainID,
|
||||
ClientID: tc.clientID,
|
||||
ClientType: tc.clientType,
|
||||
ChannelID: tc.channelID,
|
||||
Type: tc.connType,
|
||||
}
|
||||
svcCall := svc.On("Authorize", mock.Anything, authReq).Return(tc.authzErr)
|
||||
res, err := client.Authorize(context.Background(), &grpcChannelsV1.AuthzReq{
|
||||
DomainId: tc.domainID,
|
||||
ClientId: tc.clientID,
|
||||
ClientType: tc.clientType,
|
||||
ChannelId: tc.channelID,
|
||||
Type: uint32(tc.connType),
|
||||
})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.res, res, fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.res, res))
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveClientConnections(t *testing.T) {
|
||||
svc := new(mocks.Service)
|
||||
server := startGRPCServer(svc, port)
|
||||
defer server.GracefulStop()
|
||||
authAddr := fmt.Sprintf("localhost:%d", port)
|
||||
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
client := grpcapi.NewClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
clientID string
|
||||
err error
|
||||
code codes.Code
|
||||
}{
|
||||
{
|
||||
desc: "remove client connections successfully",
|
||||
clientID: validID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "remove client connections with error",
|
||||
clientID: validID,
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("RemoveClientConnections", mock.Anything, tc.clientID).Return(tc.err)
|
||||
res, err := client.RemoveClientConnections(context.Background(), &grpcChannelsV1.RemoveClientConnectionsReq{
|
||||
ClientId: tc.clientID,
|
||||
})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
|
||||
assert.Equal(t, &grpcChannelsV1.RemoveClientConnectionsRes{}, res)
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnsetParentGroupFromChannelsEndpoint(t *testing.T) {
|
||||
svc := new(mocks.Service)
|
||||
server := startGRPCServer(svc, port)
|
||||
defer server.GracefulStop()
|
||||
authAddr := fmt.Sprintf("localhost:%d", port)
|
||||
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
client := grpcapi.NewClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
parentGroupID string
|
||||
err error
|
||||
code codes.Code
|
||||
}{
|
||||
{
|
||||
desc: "unset parent group from channels successfully",
|
||||
parentGroupID: validID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "unset parent group from channels authorization error",
|
||||
parentGroupID: validID,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "unset parent group from channels with not found error",
|
||||
parentGroupID: validID,
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("UnsetParentGroupFromChannels", mock.Anything, tc.parentGroupID).Return(tc.err)
|
||||
res, err := client.UnsetParentGroupFromChannels(context.Background(), &grpcChannelsV1.UnsetParentGroupFromChannelsReq{
|
||||
ParentGroupId: tc.parentGroupID,
|
||||
})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
|
||||
assert.Equal(t, &grpcChannelsV1.UnsetParentGroupFromChannelsRes{}, res)
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveEntity(t *testing.T) {
|
||||
svc := new(mocks.Service)
|
||||
server := startGRPCServer(svc, port)
|
||||
defer server.GracefulStop()
|
||||
authAddr := fmt.Sprintf("localhost:%d", port)
|
||||
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
client := grpcapi.NewClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
svcRes ch.Channel
|
||||
resp *grpcCommonV1.RetrieveEntityRes
|
||||
code codes.Code
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "retrieve entity successfully",
|
||||
id: validID,
|
||||
svcRes: validChannel,
|
||||
resp: &grpcCommonV1.RetrieveEntityRes{
|
||||
Entity: &grpcCommonV1.EntityBasic{
|
||||
Id: validChannel.ID,
|
||||
DomainId: validChannel.Domain,
|
||||
ParentGroupId: validChannel.ParentGroup,
|
||||
Status: uint32(validChannel.Status),
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "retrieve entity with error",
|
||||
id: validID,
|
||||
resp: &grpcCommonV1.RetrieveEntityRes{},
|
||||
err: svcerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("RetrieveByID", mock.Anything, tc.id).Return(tc.svcRes, tc.err)
|
||||
res, err := client.RetrieveEntity(context.Background(), &grpcCommonV1.RetrieveEntityReq{
|
||||
Id: tc.id,
|
||||
})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.resp.Entity, res.Entity)
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import "github.com/absmach/magistrala/pkg/connections"
|
||||
|
||||
type authorizeReq struct {
|
||||
domainID string
|
||||
channelID string
|
||||
clientID string
|
||||
clientType string
|
||||
connType connections.ConnType
|
||||
}
|
||||
type removeClientConnectionsReq struct {
|
||||
clientID string
|
||||
}
|
||||
|
||||
type unsetParentGroupFromChannelsReq struct {
|
||||
parentGroupID string
|
||||
}
|
||||
|
||||
type retrieveEntityReq struct {
|
||||
Id string
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
type authorizeRes struct {
|
||||
authorized bool
|
||||
}
|
||||
|
||||
type removeClientConnectionsRes struct{}
|
||||
|
||||
type unsetParentGroupFromChannelsRes struct{}
|
||||
|
||||
type channelBasic struct {
|
||||
id string
|
||||
domain string
|
||||
parentGroup string
|
||||
status uint8
|
||||
}
|
||||
|
||||
type retrieveEntityRes channelBasic
|
||||
@@ -0,0 +1,179 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
mgauth "github.com/absmach/magistrala/auth"
|
||||
channels "github.com/absmach/magistrala/channels/private"
|
||||
grpcChannelsV1 "github.com/absmach/magistrala/internal/grpc/channels/v1"
|
||||
grpcCommonV1 "github.com/absmach/magistrala/internal/grpc/common/v1"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var _ grpcChannelsV1.ChannelsServiceServer = (*grpcServer)(nil)
|
||||
|
||||
type grpcServer struct {
|
||||
grpcChannelsV1.UnimplementedChannelsServiceServer
|
||||
authorize kitgrpc.Handler
|
||||
removeClientConnections kitgrpc.Handler
|
||||
unsetParentGroupFromChannels kitgrpc.Handler
|
||||
retrieveEntity kitgrpc.Handler
|
||||
}
|
||||
|
||||
// NewServer returns new AuthServiceServer instance.
|
||||
func NewServer(svc channels.Service) grpcChannelsV1.ChannelsServiceServer {
|
||||
return &grpcServer{
|
||||
authorize: kitgrpc.NewServer(
|
||||
authorizeEndpoint(svc),
|
||||
decodeAuthorizeRequest,
|
||||
encodeAuthorizeResponse,
|
||||
),
|
||||
removeClientConnections: kitgrpc.NewServer(
|
||||
removeClientConnectionsEndpoint(svc),
|
||||
decodeRemoveClientConnectionsRequest,
|
||||
encodeRemoveClientConnectionsResponse,
|
||||
),
|
||||
unsetParentGroupFromChannels: kitgrpc.NewServer(
|
||||
unsetParentGroupFromChannelsEndpoint(svc),
|
||||
decodeUnsetParentGroupFromChannelsRequest,
|
||||
encodeUnsetParentGroupFromChannelsResponse,
|
||||
),
|
||||
retrieveEntity: kitgrpc.NewServer(
|
||||
retrieveEntityEndpoint(svc),
|
||||
decodeRetrieveEntityRequest,
|
||||
encodeRetrieveEntityResponse,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *grpcServer) Authorize(ctx context.Context, req *grpcChannelsV1.AuthzReq) (*grpcChannelsV1.AuthzRes, error) {
|
||||
_, res, err := s.authorize.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*grpcChannelsV1.AuthzRes), nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*grpcChannelsV1.AuthzReq)
|
||||
|
||||
connType := connections.ConnType(req.GetType())
|
||||
if err := connections.CheckConnType(connType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authorizeReq{
|
||||
domainID: req.GetDomainId(),
|
||||
clientID: req.GetClientId(),
|
||||
clientType: req.GetClientType(),
|
||||
channelID: req.GetChannelId(),
|
||||
connType: connType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(authorizeRes)
|
||||
return &grpcChannelsV1.AuthzRes{Authorized: res.authorized}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) RemoveClientConnections(ctx context.Context, req *grpcChannelsV1.RemoveClientConnectionsReq) (*grpcChannelsV1.RemoveClientConnectionsRes, error) {
|
||||
_, res, err := s.removeClientConnections.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*grpcChannelsV1.RemoveClientConnectionsRes), nil
|
||||
}
|
||||
|
||||
func decodeRemoveClientConnectionsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*grpcChannelsV1.RemoveClientConnectionsReq)
|
||||
|
||||
return removeClientConnectionsReq{
|
||||
clientID: req.GetClientId(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeRemoveClientConnectionsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
_ = grpcRes.(removeClientConnectionsRes)
|
||||
return &grpcChannelsV1.RemoveClientConnectionsRes{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UnsetParentGroupFromChannels(ctx context.Context, req *grpcChannelsV1.UnsetParentGroupFromChannelsReq) (*grpcChannelsV1.UnsetParentGroupFromChannelsRes, error) {
|
||||
_, res, err := s.unsetParentGroupFromChannels.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*grpcChannelsV1.UnsetParentGroupFromChannelsRes), nil
|
||||
}
|
||||
|
||||
func decodeUnsetParentGroupFromChannelsRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*grpcChannelsV1.UnsetParentGroupFromChannelsReq)
|
||||
|
||||
return unsetParentGroupFromChannelsReq{
|
||||
parentGroupID: req.GetParentGroupId(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeUnsetParentGroupFromChannelsResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
_ = grpcRes.(unsetParentGroupFromChannelsRes)
|
||||
return &grpcChannelsV1.UnsetParentGroupFromChannelsRes{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) RetrieveEntity(ctx context.Context, req *grpcCommonV1.RetrieveEntityReq) (*grpcCommonV1.RetrieveEntityRes, error) {
|
||||
_, res, err := s.retrieveEntity.ServeGRPC(ctx, req)
|
||||
if err != nil {
|
||||
return nil, encodeError(err)
|
||||
}
|
||||
return res.(*grpcCommonV1.RetrieveEntityRes), nil
|
||||
}
|
||||
|
||||
func decodeRetrieveEntityRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
|
||||
req := grpcReq.(*grpcCommonV1.RetrieveEntityReq)
|
||||
return retrieveEntityReq{
|
||||
Id: req.GetId(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeRetrieveEntityResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
|
||||
res := grpcRes.(retrieveEntityRes)
|
||||
|
||||
return &grpcCommonV1.RetrieveEntityRes{
|
||||
Entity: &grpcCommonV1.EntityBasic{
|
||||
Id: res.id,
|
||||
DomainId: res.domain,
|
||||
ParentGroupId: res.parentGroup,
|
||||
Status: uint32(res.status),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodeError(err error) error {
|
||||
switch {
|
||||
case errors.Contains(err, nil):
|
||||
return nil
|
||||
case errors.Contains(err, errors.ErrMalformedEntity),
|
||||
err == apiutil.ErrInvalidAuthKey,
|
||||
err == apiutil.ErrMissingID,
|
||||
err == apiutil.ErrMissingMemberType,
|
||||
err == apiutil.ErrMissingPolicySub,
|
||||
err == apiutil.ErrMissingPolicyObj,
|
||||
err == apiutil.ErrMalformedPolicyAct:
|
||||
return status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Contains(err, svcerr.ErrAuthentication),
|
||||
errors.Contains(err, mgauth.ErrKeyExpired),
|
||||
err == apiutil.ErrMissingEmail,
|
||||
err == apiutil.ErrBearerToken:
|
||||
return status.Error(codes.Unauthenticated, err.Error())
|
||||
case errors.Contains(err, svcerr.ErrAuthorization):
|
||||
return status.Error(codes.PermissionDenied, err.Error())
|
||||
default:
|
||||
return status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
mgclients "github.com/absmach/magistrala/clients"
|
||||
"github.com/absmach/magistrala/internal/api"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
func decodeViewChannel(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := viewChannelReq{
|
||||
id: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeCreateChannelReq(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := createChannelReq{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req.Channel); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeCreateChannelsReq(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := createChannelsReq{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req.Channels); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListChannels(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefClientStatus)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
o, err := apiutil.ReadNumQuery[uint64](r, api.OffsetKey, api.DefOffset)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
l, err := apiutil.ReadNumQuery[uint64](r, api.LimitKey, api.DefLimit)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
m, err := apiutil.ReadMetadataQuery(r, api.MetadataKey, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
n, err := apiutil.ReadStringQuery(r, api.NameKey, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
t, err := apiutil.ReadStringQuery(r, api.TagKey, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
id, err := apiutil.ReadStringQuery(r, api.IDOrder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
p, err := apiutil.ReadStringQuery(r, api.PermissionKey, api.DefPermission)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
lp, err := apiutil.ReadBoolQuery(r, api.ListPerms, api.DefListPerms)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
st, err := mgclients.ToStatus(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
req := listChannelsReq{
|
||||
status: st,
|
||||
offset: o,
|
||||
limit: l,
|
||||
metadata: m,
|
||||
name: n,
|
||||
tag: t,
|
||||
permission: p,
|
||||
listPerms: lp,
|
||||
userID: chi.URLParam(r, "userID"),
|
||||
id: id,
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeUpdateChannel(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := updateChannelReq{
|
||||
id: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeUpdateChannelTags(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := updateChannelTagsReq{
|
||||
id: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeSetChannelParentGroupStatus(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := setChannelParentGroupReq{
|
||||
id: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeRemoveChannelParentGroupStatus(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := removeChannelParentGroupReq{
|
||||
id: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeChangeChannelStatus(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := changeChannelStatusReq{
|
||||
id: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeDeleteChannelReq(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
req := deleteChannelReq{
|
||||
id: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeConnectChannelClientRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
req := connectChannelClientsRequest{
|
||||
channelID: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeDisconnectChannelClientsRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
req := disconnectChannelClientsRequest{
|
||||
channelID: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeConnectRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := connectRequest{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeDisconnectRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := disconnectRequest{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,369 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/internal/api"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
func createChannelEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(createChannelReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
channels, err := svc.CreateChannels(ctx, session, req.Channel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return createChannelRes{
|
||||
Channel: channels[0],
|
||||
created: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func createChannelsEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(createChannelsReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
channels, err := svc.CreateChannels(ctx, session, req.Channels...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := channelsPageRes{
|
||||
pageRes: pageRes{
|
||||
Total: uint64(len(channels)),
|
||||
},
|
||||
Channels: []viewChannelRes{},
|
||||
}
|
||||
for _, c := range channels {
|
||||
res.Channels = append(res.Channels, viewChannelRes{Channel: c})
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func viewChannelEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(viewChannelReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
c, err := svc.ViewChannel(ctx, session, req.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return viewChannelRes{Channel: c}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func listChannelsEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listChannelsReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
pm := channels.PageMetadata{
|
||||
Status: req.status,
|
||||
Offset: req.offset,
|
||||
Limit: req.limit,
|
||||
Name: req.name,
|
||||
Tag: req.tag,
|
||||
Permission: req.permission,
|
||||
Metadata: req.metadata,
|
||||
ListPerms: req.listPerms,
|
||||
Id: req.id,
|
||||
}
|
||||
page, err := svc.ListChannels(ctx, session, pm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := channelsPageRes{
|
||||
pageRes: pageRes{
|
||||
Total: page.Total,
|
||||
Offset: page.Offset,
|
||||
Limit: page.Limit,
|
||||
},
|
||||
Channels: []viewChannelRes{},
|
||||
}
|
||||
for _, c := range page.Channels {
|
||||
res.Channels = append(res.Channels, viewChannelRes{Channel: c})
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func updateChannelEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(updateChannelReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
ch := channels.Channel{
|
||||
ID: req.id,
|
||||
Name: req.Name,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
ch, err := svc.UpdateChannel(ctx, session, ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return updateChannelRes{Channel: ch}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func updateChannelTagsEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(updateChannelTagsReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
ch := channels.Channel{
|
||||
ID: req.id,
|
||||
Tags: req.Tags,
|
||||
}
|
||||
ch, err := svc.UpdateChannelTags(ctx, session, ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return updateChannelRes{Channel: ch}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func setChannelParentGroupEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(setChannelParentGroupReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
if err := svc.SetParentGroup(ctx, session, req.ParentGroupID, req.id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return setChannelParentGroupRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func removeChannelParentGroupEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(removeChannelParentGroupReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
if err := svc.RemoveParentGroup(ctx, session, req.id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return removeChannelParentGroupRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func enableChannelEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(changeChannelStatusReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
ch, err := svc.EnableChannel(ctx, session, req.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return changeChannelStatusRes{Channel: ch}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func disableChannelEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(changeChannelStatusReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
ch, err := svc.DisableChannel(ctx, session, req.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return changeChannelStatusRes{Channel: ch}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func connectChannelClientEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(connectChannelClientsRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
if err := svc.Connect(ctx, session, []string{req.channelID}, req.ClientIDs, req.Types); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return connectChannelClientsRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func disconnectChannelClientsEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(disconnectChannelClientsRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
if err := svc.Disconnect(ctx, session, []string{req.channelID}, req.ClientIds, req.Types); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return disconnectChannelClientsRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func connectEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(connectRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
if err := svc.Connect(ctx, session, req.ChannelIds, req.ClientIds, req.Types); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return connectRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func disconnectEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(disconnectRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
if err := svc.Disconnect(ctx, session, req.ChannelIds, req.ClientIds, req.Types); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return disconnectRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func deleteChannelEndpoint(svc channels.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(deleteChannelReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
session, ok := ctx.Value(api.SessionKey).(authn.Session)
|
||||
if !ok {
|
||||
return nil, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
if err := svc.RemoveChannel(ctx, session, req.id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return deleteChannelRes{}, nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
mgclients "github.com/absmach/magistrala/clients"
|
||||
"github.com/absmach/magistrala/internal/api"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
)
|
||||
|
||||
type createChannelReq struct {
|
||||
Channel channels.Channel
|
||||
}
|
||||
|
||||
func (req createChannelReq) validate() error {
|
||||
if len(req.Channel.Name) > api.MaxNameSize {
|
||||
return apiutil.ErrNameSize
|
||||
}
|
||||
if req.Channel.ID != "" {
|
||||
if strings.TrimSpace(req.Channel.ID) == "" {
|
||||
return apiutil.ErrMissingChannelID
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type createChannelsReq struct {
|
||||
Channels []channels.Channel
|
||||
}
|
||||
|
||||
func (req createChannelsReq) validate() error {
|
||||
if len(req.Channels) == 0 {
|
||||
return apiutil.ErrEmptyList
|
||||
}
|
||||
for _, channel := range req.Channels {
|
||||
if channel.ID != "" {
|
||||
if strings.TrimSpace(channel.ID) == "" {
|
||||
return apiutil.ErrMissingChannelID
|
||||
}
|
||||
}
|
||||
if len(channel.Name) > api.MaxNameSize {
|
||||
return apiutil.ErrNameSize
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type viewChannelReq struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (req viewChannelReq) validate() error {
|
||||
if req.id == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type listChannelsReq struct {
|
||||
status mgclients.Status
|
||||
offset uint64
|
||||
limit uint64
|
||||
name string
|
||||
tag string
|
||||
permission string
|
||||
visibility string
|
||||
userID string
|
||||
listPerms bool
|
||||
metadata mgclients.Metadata
|
||||
id string
|
||||
}
|
||||
|
||||
func (req listChannelsReq) validate() error {
|
||||
if req.limit > api.MaxLimitSize || req.limit < 1 {
|
||||
return apiutil.ErrLimitSize
|
||||
}
|
||||
if req.visibility != "" &&
|
||||
req.visibility != api.AllVisibility &&
|
||||
req.visibility != api.MyVisibility &&
|
||||
req.visibility != api.SharedVisibility {
|
||||
return apiutil.ErrInvalidVisibilityType
|
||||
}
|
||||
if len(req.name) > api.MaxNameSize {
|
||||
return apiutil.ErrNameSize
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type updateChannelReq struct {
|
||||
id string
|
||||
Name string `json:"name,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
func (req updateChannelReq) validate() error {
|
||||
if req.id == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
if len(req.Name) > api.MaxNameSize {
|
||||
return apiutil.ErrNameSize
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type updateChannelTagsReq struct {
|
||||
id string
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
func (req updateChannelTagsReq) validate() error {
|
||||
if req.id == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type setChannelParentGroupReq struct {
|
||||
id string
|
||||
ParentGroupID string `json:"parent_group_id"`
|
||||
}
|
||||
|
||||
func (req setChannelParentGroupReq) validate() error {
|
||||
if req.id == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
if req.ParentGroupID == "" {
|
||||
return apiutil.ErrMissingParentGroupID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type removeChannelParentGroupReq struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (req removeChannelParentGroupReq) validate() error {
|
||||
if req.id == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type changeChannelStatusReq struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (req changeChannelStatusReq) validate() error {
|
||||
if req.id == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type connectChannelClientsRequest struct {
|
||||
channelID string
|
||||
ClientIDs []string `json:"client_ids,omitempty"`
|
||||
Types []connections.ConnType `json:"types,omitempty"`
|
||||
}
|
||||
|
||||
func (req *connectChannelClientsRequest) validate() error {
|
||||
if req.channelID == "" || strings.TrimSpace(req.channelID) == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
if len(req.ClientIDs) == 0 {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
for _, tid := range req.ClientIDs {
|
||||
if err := api.ValidateUUID(tid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Types) == 0 {
|
||||
return apiutil.ErrMissingConnectionType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type disconnectChannelClientsRequest struct {
|
||||
channelID string
|
||||
ClientIds []string `json:"client_ids,omitempty"`
|
||||
Types []connections.ConnType `json:"types,omitempty"`
|
||||
}
|
||||
|
||||
func (req *disconnectChannelClientsRequest) validate() error {
|
||||
if req.channelID == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
if err := api.ValidateUUID(req.channelID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(req.ClientIds) == 0 {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
for _, tid := range req.ClientIds {
|
||||
if err := api.ValidateUUID(tid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Types) == 0 {
|
||||
return apiutil.ErrMissingConnectionType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type connectRequest struct {
|
||||
ChannelIds []string `json:"channel_ids,omitempty"`
|
||||
ClientIds []string `json:"client_ids,omitempty"`
|
||||
Types []connections.ConnType `json:"types,omitempty"`
|
||||
}
|
||||
|
||||
func (req *connectRequest) validate() error {
|
||||
if len(req.ChannelIds) == 0 {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
for _, cid := range req.ChannelIds {
|
||||
if strings.TrimSpace(cid) == "" {
|
||||
return apiutil.ErrMissingChannelID
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.ClientIds) == 0 {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
for _, tid := range req.ClientIds {
|
||||
if strings.TrimSpace(tid) == "" {
|
||||
return apiutil.ErrMissingChannelID
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Types) == 0 {
|
||||
return apiutil.ErrMissingConnectionType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type disconnectRequest struct {
|
||||
ChannelIds []string `json:"channel_ids,omitempty"`
|
||||
ClientIds []string `json:"client_ids,omitempty"`
|
||||
Types []connections.ConnType `json:"types,omitempty"`
|
||||
}
|
||||
|
||||
func (req *disconnectRequest) validate() error {
|
||||
if len(req.ChannelIds) == 0 {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
for _, cid := range req.ChannelIds {
|
||||
if err := api.ValidateUUID(cid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.ClientIds) == 0 {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
|
||||
for _, tid := range req.ClientIds {
|
||||
if err := api.ValidateUUID(tid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Types) == 0 {
|
||||
return apiutil.ErrMissingConnectionType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type deleteChannelReq struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (req deleteChannelReq) validate() error {
|
||||
if req.id == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,613 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/internal/api"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateChannelReqValidation(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req createChannelReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: createChannelReq{
|
||||
Channel: channels.Channel{
|
||||
Name: valid,
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "long name",
|
||||
req: createChannelReq{
|
||||
Channel: channels.Channel{
|
||||
Name: strings.Repeat("a", api.MaxNameSize+1),
|
||||
},
|
||||
},
|
||||
err: apiutil.ErrNameSize,
|
||||
},
|
||||
{
|
||||
desc: "missing channel ID",
|
||||
req: createChannelReq{
|
||||
Channel: channels.Channel{
|
||||
ID: " ",
|
||||
},
|
||||
},
|
||||
err: apiutil.ErrMissingChannelID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateChannelsReqValidation(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req createChannelsReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: createChannelsReq{
|
||||
Channels: []channels.Channel{
|
||||
{
|
||||
Name: valid,
|
||||
},
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "long name",
|
||||
req: createChannelsReq{
|
||||
Channels: []channels.Channel{
|
||||
{
|
||||
Name: strings.Repeat("a", api.MaxNameSize+1),
|
||||
},
|
||||
},
|
||||
},
|
||||
err: apiutil.ErrNameSize,
|
||||
},
|
||||
{
|
||||
desc: "missing channel ID",
|
||||
req: createChannelsReq{
|
||||
Channels: []channels.Channel{
|
||||
{
|
||||
ID: " ",
|
||||
},
|
||||
},
|
||||
},
|
||||
err: apiutil.ErrMissingChannelID,
|
||||
},
|
||||
{
|
||||
desc: "empty list",
|
||||
req: createChannelsReq{
|
||||
Channels: []channels.Channel{},
|
||||
},
|
||||
err: apiutil.ErrEmptyList,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewChannelReqValidation(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req viewChannelReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: viewChannelReq{
|
||||
id: valid,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing ID",
|
||||
req: viewChannelReq{
|
||||
id: "",
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestListChannelsReqValidation(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req listChannelsReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: listChannelsReq{
|
||||
limit: 10,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "limit is 0",
|
||||
req: listChannelsReq{
|
||||
limit: 0,
|
||||
},
|
||||
err: apiutil.ErrLimitSize,
|
||||
},
|
||||
{
|
||||
desc: "limit is greater than max limit",
|
||||
req: listChannelsReq{
|
||||
limit: api.MaxLimitSize + 1,
|
||||
},
|
||||
err: apiutil.ErrLimitSize,
|
||||
},
|
||||
{
|
||||
desc: "name is too long",
|
||||
req: listChannelsReq{
|
||||
limit: 10,
|
||||
name: strings.Repeat("a", api.MaxNameSize+1),
|
||||
},
|
||||
err: apiutil.ErrNameSize,
|
||||
},
|
||||
{
|
||||
desc: "invalid visibility",
|
||||
req: listChannelsReq{
|
||||
limit: 10,
|
||||
visibility: "invalid",
|
||||
},
|
||||
err: apiutil.ErrInvalidVisibilityType,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateChannelReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req updateChannelReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: updateChannelReq{
|
||||
id: valid,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing ID",
|
||||
req: updateChannelReq{
|
||||
id: "",
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "name is too long",
|
||||
req: updateChannelReq{
|
||||
id: valid,
|
||||
Name: strings.Repeat("a", api.MaxNameSize+1),
|
||||
},
|
||||
err: apiutil.ErrNameSize,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateChannelTagsReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req updateChannelTagsReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: updateChannelTagsReq{
|
||||
id: valid,
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing ID",
|
||||
req: updateChannelTagsReq{
|
||||
id: "",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetChannelsParentGroupReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req setChannelParentGroupReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: setChannelParentGroupReq{
|
||||
id: valid,
|
||||
ParentGroupID: valid,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing ID",
|
||||
req: setChannelParentGroupReq{
|
||||
id: "",
|
||||
ParentGroupID: valid,
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing parent group ID",
|
||||
req: setChannelParentGroupReq{
|
||||
id: valid,
|
||||
ParentGroupID: "",
|
||||
},
|
||||
err: apiutil.ErrMissingParentGroupID,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveChannelParentGroupReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req removeChannelParentGroupReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: removeChannelParentGroupReq{
|
||||
id: valid,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing ID",
|
||||
req: removeChannelParentGroupReq{
|
||||
id: "",
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangeChannelStatusReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req changeChannelStatusReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: changeChannelStatusReq{
|
||||
id: valid,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing ID",
|
||||
req: changeChannelStatusReq{
|
||||
id: "",
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectChannelClientsReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req connectChannelClientsRequest
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: connectChannelClientsRequest{
|
||||
channelID: valid,
|
||||
ClientIDs: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing channel ID",
|
||||
req: connectChannelClientsRequest{
|
||||
channelID: "",
|
||||
ClientIDs: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing client IDs",
|
||||
req: connectChannelClientsRequest{
|
||||
channelID: valid,
|
||||
ClientIDs: []string{},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing connection types",
|
||||
req: connectChannelClientsRequest{
|
||||
channelID: valid,
|
||||
ClientIDs: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{},
|
||||
},
|
||||
err: apiutil.ErrMissingConnectionType,
|
||||
},
|
||||
{
|
||||
desc: "invalid client ID",
|
||||
req: connectChannelClientsRequest{
|
||||
channelID: valid,
|
||||
ClientIDs: []string{"client1", "invalid"},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrInvalidIDFormat,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectChannelClientReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req disconnectChannelClientsRequest
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: disconnectChannelClientsRequest{
|
||||
channelID: testsutil.GenerateUUID(t),
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing channel ID",
|
||||
req: disconnectChannelClientsRequest{
|
||||
channelID: "",
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "invalid channel ID",
|
||||
req: disconnectChannelClientsRequest{
|
||||
channelID: "invalid",
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrInvalidIDFormat,
|
||||
},
|
||||
{
|
||||
desc: "missing client IDs",
|
||||
req: disconnectChannelClientsRequest{
|
||||
channelID: testsutil.GenerateUUID(t),
|
||||
ClientIds: []string{},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing connection types",
|
||||
req: disconnectChannelClientsRequest{
|
||||
channelID: testsutil.GenerateUUID(t),
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{},
|
||||
},
|
||||
err: apiutil.ErrMissingConnectionType,
|
||||
},
|
||||
{
|
||||
desc: "invalid client ID",
|
||||
req: disconnectChannelClientsRequest{
|
||||
channelID: testsutil.GenerateUUID(t),
|
||||
ClientIds: []string{"client1", "invalid"},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrInvalidIDFormat,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req connectRequest
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: connectRequest{
|
||||
ChannelIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing channel IDs",
|
||||
req: connectRequest{
|
||||
ChannelIds: []string{},
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing client IDs",
|
||||
req: connectRequest{
|
||||
ChannelIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing connection types",
|
||||
req: connectRequest{
|
||||
ChannelIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{},
|
||||
},
|
||||
err: apiutil.ErrMissingConnectionType,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisconnectReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req disconnectRequest
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: disconnectRequest{
|
||||
ChannelIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing channel IDs",
|
||||
req: disconnectRequest{
|
||||
ChannelIds: []string{},
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing client IDs",
|
||||
req: disconnectRequest{
|
||||
ChannelIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "missing connection types",
|
||||
req: disconnectRequest{
|
||||
ChannelIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{},
|
||||
},
|
||||
err: apiutil.ErrMissingConnectionType,
|
||||
},
|
||||
{
|
||||
desc: "invalid client ID",
|
||||
req: disconnectRequest{
|
||||
ChannelIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{"client1", "invalid"},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrInvalidIDFormat,
|
||||
},
|
||||
{
|
||||
desc: "invalid channel ID",
|
||||
req: disconnectRequest{
|
||||
ChannelIds: []string{"invalid", testsutil.GenerateUUID(t)},
|
||||
ClientIds: []string{testsutil.GenerateUUID(t), testsutil.GenerateUUID(t)},
|
||||
Types: []connections.ConnType{connections.Publish},
|
||||
},
|
||||
err: apiutil.ErrInvalidIDFormat,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteChannelReqValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
req deleteChannelReq
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request",
|
||||
req: deleteChannelReq{
|
||||
id: valid,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "missing ID",
|
||||
req: deleteChannelReq{
|
||||
id: "",
|
||||
},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := tc.req.validate()
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/channels"
|
||||
)
|
||||
|
||||
var (
|
||||
_ magistrala.Response = (*createChannelRes)(nil)
|
||||
_ magistrala.Response = (*viewChannelRes)(nil)
|
||||
_ magistrala.Response = (*channelsPageRes)(nil)
|
||||
_ magistrala.Response = (*updateChannelRes)(nil)
|
||||
_ magistrala.Response = (*deleteChannelRes)(nil)
|
||||
_ magistrala.Response = (*connectChannelClientsRes)(nil)
|
||||
_ magistrala.Response = (*disconnectChannelClientsRes)(nil)
|
||||
_ magistrala.Response = (*connectRes)(nil)
|
||||
_ magistrala.Response = (*disconnectRes)(nil)
|
||||
_ magistrala.Response = (*changeChannelStatusRes)(nil)
|
||||
)
|
||||
|
||||
type pageRes struct {
|
||||
Limit uint64 `json:"limit,omitempty"`
|
||||
Offset uint64 `json:"offset"`
|
||||
Total uint64 `json:"total"`
|
||||
}
|
||||
|
||||
type createChannelRes struct {
|
||||
channels.Channel
|
||||
created bool
|
||||
}
|
||||
|
||||
func (res createChannelRes) Code() int {
|
||||
if res.created {
|
||||
return http.StatusCreated
|
||||
}
|
||||
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res createChannelRes) Headers() map[string]string {
|
||||
if res.created {
|
||||
return map[string]string{
|
||||
"Location": fmt.Sprintf("/channels/%s", res.ID),
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res createChannelRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type viewChannelRes struct {
|
||||
channels.Channel
|
||||
}
|
||||
|
||||
func (res viewChannelRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res viewChannelRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res viewChannelRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type channelsPageRes struct {
|
||||
pageRes
|
||||
Channels []viewChannelRes `json:"channels"`
|
||||
}
|
||||
|
||||
func (res channelsPageRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res channelsPageRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res channelsPageRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type changeChannelStatusRes struct {
|
||||
channels.Channel
|
||||
}
|
||||
|
||||
func (res changeChannelStatusRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res changeChannelStatusRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res changeChannelStatusRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type updateChannelRes struct {
|
||||
channels.Channel
|
||||
}
|
||||
|
||||
func (res updateChannelRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res updateChannelRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res updateChannelRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type setChannelParentGroupRes struct{}
|
||||
|
||||
func (res setChannelParentGroupRes) Code() int {
|
||||
return http.StatusAccepted
|
||||
}
|
||||
|
||||
func (res setChannelParentGroupRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res setChannelParentGroupRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type removeChannelParentGroupRes struct{}
|
||||
|
||||
func (res removeChannelParentGroupRes) Code() int {
|
||||
return http.StatusNoContent
|
||||
}
|
||||
|
||||
func (res removeChannelParentGroupRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res removeChannelParentGroupRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type deleteChannelRes struct{}
|
||||
|
||||
func (res deleteChannelRes) Code() int {
|
||||
return http.StatusNoContent
|
||||
}
|
||||
|
||||
func (res deleteChannelRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res deleteChannelRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type connectChannelClientsRes struct{}
|
||||
|
||||
func (res connectChannelClientsRes) Code() int {
|
||||
return http.StatusCreated
|
||||
}
|
||||
|
||||
func (res connectChannelClientsRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res connectChannelClientsRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type disconnectChannelClientsRes struct{}
|
||||
|
||||
func (res disconnectChannelClientsRes) Code() int {
|
||||
return http.StatusNoContent
|
||||
}
|
||||
|
||||
func (res disconnectChannelClientsRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res disconnectChannelClientsRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type connectRes struct{}
|
||||
|
||||
func (res connectRes) Code() int {
|
||||
return http.StatusCreated
|
||||
}
|
||||
|
||||
func (res connectRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res connectRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type disconnectRes struct{}
|
||||
|
||||
func (res disconnectRes) Code() int {
|
||||
return http.StatusNoContent
|
||||
}
|
||||
|
||||
func (res disconnectRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res disconnectRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/internal/api"
|
||||
"github.com/absmach/magistrala/pkg/apiutil"
|
||||
mgauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/go-chi/chi/v5"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP handler for Channels API endpoints.
|
||||
func MakeHandler(svc channels.Service, authn mgauthn.Authentication, mux *chi.Mux, logger *slog.Logger, instanceID string) *chi.Mux {
|
||||
opts := []kithttp.ServerOption{
|
||||
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)),
|
||||
}
|
||||
mux.Route("/{domainID}/channels", func(r chi.Router) {
|
||||
r.Use(api.AuthenticateMiddleware(authn, true))
|
||||
|
||||
r.Post("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
createChannelEndpoint(svc),
|
||||
decodeCreateChannelReq,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "create_channel").ServeHTTP)
|
||||
|
||||
r.Post("/bulk", otelhttp.NewHandler(kithttp.NewServer(
|
||||
createChannelsEndpoint(svc),
|
||||
decodeCreateChannelsReq,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "create_channels").ServeHTTP)
|
||||
|
||||
r.Get("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listChannelsEndpoint(svc),
|
||||
decodeListChannels,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "list_channels").ServeHTTP)
|
||||
|
||||
r.Post("/connect", otelhttp.NewHandler(kithttp.NewServer(
|
||||
connectEndpoint(svc),
|
||||
decodeConnectRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "connect").ServeHTTP)
|
||||
|
||||
r.Post("/disconnect", otelhttp.NewHandler(kithttp.NewServer(
|
||||
disconnectEndpoint(svc),
|
||||
decodeDisconnectRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "disconnect").ServeHTTP)
|
||||
|
||||
r.Route("/{channelID}", func(r chi.Router) {
|
||||
r.Get("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
viewChannelEndpoint(svc),
|
||||
decodeViewChannel,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "view_channel").ServeHTTP)
|
||||
|
||||
r.Patch("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
updateChannelEndpoint(svc),
|
||||
decodeUpdateChannel,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "update_channel_name_and_metadata").ServeHTTP)
|
||||
|
||||
r.Patch("/tags", otelhttp.NewHandler(kithttp.NewServer(
|
||||
updateChannelTagsEndpoint(svc),
|
||||
decodeUpdateChannelTags,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "update_channel_tag").ServeHTTP)
|
||||
|
||||
r.Delete("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
deleteChannelEndpoint(svc),
|
||||
decodeDeleteChannelReq,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "delete_channel").ServeHTTP)
|
||||
|
||||
r.Post("/enable", otelhttp.NewHandler(kithttp.NewServer(
|
||||
enableChannelEndpoint(svc),
|
||||
decodeChangeChannelStatus,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "enable_channel").ServeHTTP)
|
||||
|
||||
r.Post("/disable", otelhttp.NewHandler(kithttp.NewServer(
|
||||
disableChannelEndpoint(svc),
|
||||
decodeChangeChannelStatus,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "disable_channel").ServeHTTP)
|
||||
|
||||
r.Post("/parent", otelhttp.NewHandler(kithttp.NewServer(
|
||||
setChannelParentGroupEndpoint(svc),
|
||||
decodeSetChannelParentGroupStatus,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "set_channel_parent_group").ServeHTTP)
|
||||
|
||||
r.Delete("/parent", otelhttp.NewHandler(kithttp.NewServer(
|
||||
removeChannelParentGroupEndpoint(svc),
|
||||
decodeRemoveChannelParentGroupStatus,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "remove_channel_parent_group").ServeHTTP)
|
||||
|
||||
r.Post("/connect", otelhttp.NewHandler(kithttp.NewServer(
|
||||
connectChannelClientEndpoint(svc),
|
||||
decodeConnectChannelClientRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "connect_channel_client").ServeHTTP)
|
||||
|
||||
r.Post("/disconnect", otelhttp.NewHandler(kithttp.NewServer(
|
||||
disconnectChannelClientsEndpoint(svc),
|
||||
decodeDisconnectChannelClientsRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "disconnect_channel_client").ServeHTTP)
|
||||
})
|
||||
})
|
||||
|
||||
mux.Get("/health", magistrala.Health("channels", instanceID))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return mux
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
clients "github.com/absmach/magistrala/clients"
|
||||
"github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/roles"
|
||||
)
|
||||
|
||||
// Channel represents a Magistrala "communication topic". This topic
|
||||
// contains the clients that can exchange messages between each other.
|
||||
type Channel struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
ParentGroup string `json:"parent_group_id,omitempty"`
|
||||
Domain string `json:"domain_id,omitempty"`
|
||||
Metadata clients.Metadata `json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
UpdatedBy string `json:"updated_by,omitempty"`
|
||||
Status clients.Status `json:"status,omitempty"` // 1 for enabled, 0 for disabled
|
||||
Permissions []string `json:"permissions,omitempty"` // 1 for enabled, 0 for disabled
|
||||
}
|
||||
|
||||
type PageMetadata struct {
|
||||
Total uint64 `json:"total"`
|
||||
Offset uint64 `json:"offset"`
|
||||
Limit uint64 `json:"limit"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
Order string `json:"order,omitempty"`
|
||||
Dir string `json:"dir,omitempty"`
|
||||
Metadata clients.Metadata `json:"metadata,omitempty"`
|
||||
Domain string `json:"domain,omitempty"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Permission string `json:"permission,omitempty"`
|
||||
Status clients.Status `json:"status,omitempty"`
|
||||
IDs []string `json:"ids,omitempty"`
|
||||
ListPerms bool `json:"-"`
|
||||
ClientID string `json:"-"`
|
||||
}
|
||||
|
||||
// ChannelsPage contains page related metadata as well as list of channels that
|
||||
// belong to this page.
|
||||
type Page struct {
|
||||
PageMetadata
|
||||
Channels []Channel
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
ClientID string
|
||||
ChannelID string
|
||||
DomainID string
|
||||
Type connections.ConnType
|
||||
}
|
||||
|
||||
type AuthzReq struct {
|
||||
DomainID string
|
||||
ChannelID string
|
||||
ClientID string
|
||||
ClientType string
|
||||
Type connections.ConnType
|
||||
}
|
||||
|
||||
//go:generate mockery --name Service --output=./mocks --filename service.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type Service interface {
|
||||
// CreateChannels adds channels to the user identified by the provided key.
|
||||
CreateChannels(ctx context.Context, session authn.Session, channels ...Channel) ([]Channel, error)
|
||||
|
||||
// ViewChannel retrieves data about the channel identified by the provided
|
||||
// ID, that belongs to the user identified by the provided key.
|
||||
ViewChannel(ctx context.Context, session authn.Session, id string) (Channel, error)
|
||||
|
||||
// UpdateChannel updates the channel identified by the provided ID, that
|
||||
// belongs to the user identified by the provided key.
|
||||
UpdateChannel(ctx context.Context, session authn.Session, channel Channel) (Channel, error)
|
||||
|
||||
// UpdateChannelTags updates the channel's tags.
|
||||
UpdateChannelTags(ctx context.Context, session authn.Session, channel Channel) (Channel, error)
|
||||
|
||||
EnableChannel(ctx context.Context, session authn.Session, id string) (Channel, error)
|
||||
|
||||
DisableChannel(ctx context.Context, session authn.Session, id string) (Channel, error)
|
||||
|
||||
// ListChannels retrieves data about subset of channels that belongs to the
|
||||
// user identified by the provided key.
|
||||
ListChannels(ctx context.Context, session authn.Session, pm PageMetadata) (Page, error)
|
||||
|
||||
// ListChannelsByClient retrieves data about subset of channels that have
|
||||
// specified client connected or not connected to them and belong to the user identified by
|
||||
// the provided key.
|
||||
ListChannelsByClient(ctx context.Context, session authn.Session, id string, pm PageMetadata) (Page, error)
|
||||
|
||||
// RemoveChannel removes the client identified by the provided ID, that
|
||||
// belongs to the user identified by the provided key.
|
||||
RemoveChannel(ctx context.Context, session authn.Session, id string) error
|
||||
|
||||
// Connect adds clients to the channels list of connected clients.
|
||||
Connect(ctx context.Context, session authn.Session, chIDs, clIDs []string, connType []connections.ConnType) error
|
||||
|
||||
// Disconnect removes clients from the channels list of connected clients.
|
||||
Disconnect(ctx context.Context, session authn.Session, chIDs, clIDs []string, connType []connections.ConnType) error
|
||||
|
||||
SetParentGroup(ctx context.Context, session authn.Session, parentGroupID string, id string) error
|
||||
|
||||
RemoveParentGroup(ctx context.Context, session authn.Session, id string) error
|
||||
|
||||
roles.RoleManager
|
||||
}
|
||||
|
||||
// ChannelRepository specifies a channel persistence API.
|
||||
//
|
||||
//go:generate mockery --name Repository --output=./mocks --filename repository.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type Repository interface {
|
||||
// Save persists multiple channels. Channels are saved using a transaction. If one channel
|
||||
// fails then none will be saved. Successful operation is indicated by non-nil
|
||||
// error response.
|
||||
Save(ctx context.Context, chs ...Channel) ([]Channel, error)
|
||||
|
||||
// Update performs an update to the existing channel.
|
||||
Update(ctx context.Context, c Channel) (Channel, error)
|
||||
|
||||
UpdateTags(ctx context.Context, ch Channel) (Channel, error)
|
||||
|
||||
ChangeStatus(ctx context.Context, channel Channel) (Channel, error)
|
||||
|
||||
// RetrieveByID retrieves the channel having the provided identifier
|
||||
RetrieveByID(ctx context.Context, id string) (Channel, error)
|
||||
|
||||
// RetrieveAll retrieves the subset of channels.
|
||||
RetrieveAll(ctx context.Context, pm PageMetadata) (Page, error)
|
||||
|
||||
// Remove removes the channel having the provided identifier
|
||||
Remove(ctx context.Context, ids ...string) error
|
||||
|
||||
// SetParentGroup set parent group id to a given channel id
|
||||
SetParentGroup(ctx context.Context, ch Channel) error
|
||||
|
||||
// RemoveParentGroup remove parent group id fr given chanel id
|
||||
RemoveParentGroup(ctx context.Context, ch Channel) error
|
||||
|
||||
AddConnections(ctx context.Context, conns []Connection) error
|
||||
|
||||
RemoveConnections(ctx context.Context, conns []Connection) error
|
||||
|
||||
CheckConnection(ctx context.Context, conn Connection) error
|
||||
|
||||
ClientAuthorize(ctx context.Context, conn Connection) error
|
||||
|
||||
ChannelConnectionsCount(ctx context.Context, id string) (uint64, error)
|
||||
|
||||
DoesChannelHaveConnections(ctx context.Context, id string) (bool, error)
|
||||
|
||||
RemoveClientConnections(ctx context.Context, clientID string) error
|
||||
|
||||
RemoveChannelConnections(ctx context.Context, channelID string) error
|
||||
|
||||
RetrieveParentGroupChannels(ctx context.Context, parentGroupID string) ([]Channel, error)
|
||||
|
||||
UnsetParentGroupFromChannels(ctx context.Context, parentGroupID string) error
|
||||
|
||||
roles.Repository
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package events provides the domain concept definitions
|
||||
// needed to support clients events functionality.
|
||||
package events
|
||||
@@ -0,0 +1,313 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/events"
|
||||
)
|
||||
|
||||
const (
|
||||
channelPrefix = "channels."
|
||||
channelCreate = channelPrefix + "create"
|
||||
channelUpdate = channelPrefix + "update"
|
||||
channelChangeStatus = channelPrefix + "change_status"
|
||||
channelRemove = channelPrefix + "remove"
|
||||
channelView = channelPrefix + "view"
|
||||
channelList = channelPrefix + "list"
|
||||
channelConnect = channelPrefix + "connect"
|
||||
channelDisconnect = channelPrefix + "disconnect"
|
||||
channelSetParent = channelPrefix + "set_parent"
|
||||
channelRemoveParent = channelPrefix + "remove_parent"
|
||||
)
|
||||
|
||||
var (
|
||||
_ events.Event = (*createChannelEvent)(nil)
|
||||
_ events.Event = (*updateChannelEvent)(nil)
|
||||
_ events.Event = (*changeStatusChannelEvent)(nil)
|
||||
_ events.Event = (*viewChannelEvent)(nil)
|
||||
_ events.Event = (*listChannelEvent)(nil)
|
||||
_ events.Event = (*removeChannelEvent)(nil)
|
||||
_ events.Event = (*connectEvent)(nil)
|
||||
_ events.Event = (*disconnectEvent)(nil)
|
||||
)
|
||||
|
||||
type createChannelEvent struct {
|
||||
channels.Channel
|
||||
}
|
||||
|
||||
func (cce createChannelEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"operation": channelCreate,
|
||||
"id": cce.ID,
|
||||
"status": cce.Status.String(),
|
||||
"created_at": cce.CreatedAt,
|
||||
}
|
||||
|
||||
if cce.Name != "" {
|
||||
val["name"] = cce.Name
|
||||
}
|
||||
if len(cce.Tags) > 0 {
|
||||
val["tags"] = cce.Tags
|
||||
}
|
||||
if cce.Domain != "" {
|
||||
val["domain"] = cce.Domain
|
||||
}
|
||||
if cce.Metadata != nil {
|
||||
val["metadata"] = cce.Metadata
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
type updateChannelEvent struct {
|
||||
channels.Channel
|
||||
operation string
|
||||
}
|
||||
|
||||
func (uce updateChannelEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"operation": channelUpdate,
|
||||
"updated_at": uce.UpdatedAt,
|
||||
"updated_by": uce.UpdatedBy,
|
||||
}
|
||||
if uce.operation != "" {
|
||||
val["operation"] = channelUpdate + "_" + uce.operation
|
||||
}
|
||||
|
||||
if uce.ID != "" {
|
||||
val["id"] = uce.ID
|
||||
}
|
||||
if uce.Name != "" {
|
||||
val["name"] = uce.Name
|
||||
}
|
||||
if len(uce.Tags) > 0 {
|
||||
val["tags"] = uce.Tags
|
||||
}
|
||||
if uce.Domain != "" {
|
||||
val["domain"] = uce.Domain
|
||||
}
|
||||
if uce.Metadata != nil {
|
||||
val["metadata"] = uce.Metadata
|
||||
}
|
||||
if !uce.CreatedAt.IsZero() {
|
||||
val["created_at"] = uce.CreatedAt
|
||||
}
|
||||
if uce.Status.String() != "" {
|
||||
val["status"] = uce.Status.String()
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
type changeStatusChannelEvent struct {
|
||||
id string
|
||||
status string
|
||||
updatedAt time.Time
|
||||
updatedBy string
|
||||
}
|
||||
|
||||
func (rce changeStatusChannelEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"operation": channelChangeStatus,
|
||||
"id": rce.id,
|
||||
"status": rce.status,
|
||||
"updated_at": rce.updatedAt,
|
||||
"updated_by": rce.updatedBy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type viewChannelEvent struct {
|
||||
channels.Channel
|
||||
}
|
||||
|
||||
func (vce viewChannelEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"operation": channelView,
|
||||
"id": vce.ID,
|
||||
}
|
||||
|
||||
if vce.Name != "" {
|
||||
val["name"] = vce.Name
|
||||
}
|
||||
if len(vce.Tags) > 0 {
|
||||
val["tags"] = vce.Tags
|
||||
}
|
||||
if vce.Domain != "" {
|
||||
val["domain"] = vce.Domain
|
||||
}
|
||||
if vce.Metadata != nil {
|
||||
val["metadata"] = vce.Metadata
|
||||
}
|
||||
if !vce.CreatedAt.IsZero() {
|
||||
val["created_at"] = vce.CreatedAt
|
||||
}
|
||||
if !vce.UpdatedAt.IsZero() {
|
||||
val["updated_at"] = vce.UpdatedAt
|
||||
}
|
||||
if vce.UpdatedBy != "" {
|
||||
val["updated_by"] = vce.UpdatedBy
|
||||
}
|
||||
if vce.Status.String() != "" {
|
||||
val["status"] = vce.Status.String()
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
type listChannelEvent struct {
|
||||
channels.PageMetadata
|
||||
}
|
||||
|
||||
func (lce listChannelEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"operation": channelList,
|
||||
"total": lce.Total,
|
||||
"offset": lce.Offset,
|
||||
"limit": lce.Limit,
|
||||
}
|
||||
|
||||
if lce.Name != "" {
|
||||
val["name"] = lce.Name
|
||||
}
|
||||
if lce.Order != "" {
|
||||
val["order"] = lce.Order
|
||||
}
|
||||
if lce.Dir != "" {
|
||||
val["dir"] = lce.Dir
|
||||
}
|
||||
if lce.Metadata != nil {
|
||||
val["metadata"] = lce.Metadata
|
||||
}
|
||||
if lce.Domain != "" {
|
||||
val["domain"] = lce.Domain
|
||||
}
|
||||
if lce.Tag != "" {
|
||||
val["tag"] = lce.Tag
|
||||
}
|
||||
if lce.Permission != "" {
|
||||
val["permission"] = lce.Permission
|
||||
}
|
||||
if lce.Status.String() != "" {
|
||||
val["status"] = lce.Status.String()
|
||||
}
|
||||
if len(lce.IDs) > 0 {
|
||||
val["ids"] = lce.IDs
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
type listChannelByClientEvent struct {
|
||||
clientID string
|
||||
channels.PageMetadata
|
||||
}
|
||||
|
||||
func (lcte listChannelByClientEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"operation": channelList,
|
||||
"client_id": lcte.clientID,
|
||||
"total": lcte.Total,
|
||||
"offset": lcte.Offset,
|
||||
"limit": lcte.Limit,
|
||||
}
|
||||
|
||||
if lcte.Name != "" {
|
||||
val["name"] = lcte.Name
|
||||
}
|
||||
if lcte.Order != "" {
|
||||
val["order"] = lcte.Order
|
||||
}
|
||||
if lcte.Dir != "" {
|
||||
val["dir"] = lcte.Dir
|
||||
}
|
||||
if lcte.Metadata != nil {
|
||||
val["metadata"] = lcte.Metadata
|
||||
}
|
||||
if lcte.Domain != "" {
|
||||
val["domain"] = lcte.Domain
|
||||
}
|
||||
if lcte.Tag != "" {
|
||||
val["tag"] = lcte.Tag
|
||||
}
|
||||
if lcte.Permission != "" {
|
||||
val["permission"] = lcte.Permission
|
||||
}
|
||||
if lcte.Status.String() != "" {
|
||||
val["status"] = lcte.Status.String()
|
||||
}
|
||||
if len(lcte.IDs) > 0 {
|
||||
val["ids"] = lcte.IDs
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
type removeChannelEvent struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (dce removeChannelEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"operation": channelRemove,
|
||||
"id": dce.id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type connectEvent struct {
|
||||
chIDs []string
|
||||
thIDs []string
|
||||
types []connections.ConnType
|
||||
}
|
||||
|
||||
func (ce connectEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"operation": channelConnect,
|
||||
"client_ids": ce.thIDs,
|
||||
"channel_ids": ce.chIDs,
|
||||
"types": ce.types,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type disconnectEvent struct {
|
||||
chIDs []string
|
||||
thIDs []string
|
||||
types []connections.ConnType
|
||||
}
|
||||
|
||||
func (de disconnectEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"operation": channelDisconnect,
|
||||
"client_ids": de.thIDs,
|
||||
"channel_ids": de.chIDs,
|
||||
"types": de.types,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type setParentGroupEvent struct {
|
||||
id string
|
||||
parentGroupID string
|
||||
}
|
||||
|
||||
func (spge setParentGroupEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"operation": channelSetParent,
|
||||
"id": spge.id,
|
||||
"parent_group_id": spge.parentGroupID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type removeParentGroupEvent struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (rpge removeParentGroupEvent) Encode() (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"operation": channelRemoveParent,
|
||||
"id": rpge.id,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/events"
|
||||
"github.com/absmach/magistrala/pkg/events/store"
|
||||
rmEvents "github.com/absmach/magistrala/pkg/roles/rolemanager/events"
|
||||
)
|
||||
|
||||
const streamID = "magistrala.clients"
|
||||
|
||||
var _ channels.Service = (*eventStore)(nil)
|
||||
|
||||
type eventStore struct {
|
||||
events.Publisher
|
||||
svc channels.Service
|
||||
rmEvents.RoleManagerEventStore
|
||||
}
|
||||
|
||||
// NewEventStoreMiddleware returns wrapper around clients service that sends
|
||||
// events to event store.
|
||||
func NewEventStoreMiddleware(ctx context.Context, svc channels.Service, url string) (channels.Service, error) {
|
||||
publisher, err := store.NewPublisher(ctx, url, streamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rolesSvcEventStoreMiddleware := rmEvents.NewRoleManagerEventStore("channels", svc, publisher)
|
||||
return &eventStore{
|
||||
svc: svc,
|
||||
Publisher: publisher,
|
||||
RoleManagerEventStore: rolesSvcEventStoreMiddleware,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) CreateChannels(ctx context.Context, session authn.Session, chs ...channels.Channel) ([]channels.Channel, error) {
|
||||
chs, err := es.svc.CreateChannels(ctx, session, chs...)
|
||||
if err != nil {
|
||||
return chs, err
|
||||
}
|
||||
|
||||
for _, ch := range chs {
|
||||
event := createChannelEvent{
|
||||
ch,
|
||||
}
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return chs, err
|
||||
}
|
||||
}
|
||||
|
||||
return chs, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) UpdateChannel(ctx context.Context, session authn.Session, ch channels.Channel) (channels.Channel, error) {
|
||||
chann, err := es.svc.UpdateChannel(ctx, session, ch)
|
||||
if err != nil {
|
||||
return chann, err
|
||||
}
|
||||
|
||||
return es.update(ctx, "", chann)
|
||||
}
|
||||
|
||||
func (es *eventStore) UpdateChannelTags(ctx context.Context, session authn.Session, ch channels.Channel) (channels.Channel, error) {
|
||||
chann, err := es.svc.UpdateChannelTags(ctx, session, ch)
|
||||
if err != nil {
|
||||
return chann, err
|
||||
}
|
||||
|
||||
return es.update(ctx, "tags", chann)
|
||||
}
|
||||
|
||||
func (es *eventStore) update(ctx context.Context, operation string, ch channels.Channel) (channels.Channel, error) {
|
||||
event := updateChannelEvent{
|
||||
ch, operation,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return ch, err
|
||||
}
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ViewChannel(ctx context.Context, session authn.Session, id string) (channels.Channel, error) {
|
||||
chann, err := es.svc.ViewChannel(ctx, session, id)
|
||||
if err != nil {
|
||||
return chann, err
|
||||
}
|
||||
|
||||
event := viewChannelEvent{
|
||||
chann,
|
||||
}
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return chann, err
|
||||
}
|
||||
|
||||
return chann, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ListChannels(ctx context.Context, session authn.Session, pm channels.PageMetadata) (channels.Page, error) {
|
||||
cp, err := es.svc.ListChannels(ctx, session, pm)
|
||||
if err != nil {
|
||||
return cp, err
|
||||
}
|
||||
event := listChannelEvent{
|
||||
pm,
|
||||
}
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return cp, err
|
||||
}
|
||||
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ListChannelsByClient(ctx context.Context, session authn.Session, clientID string, pm channels.PageMetadata) (channels.Page, error) {
|
||||
cp, err := es.svc.ListChannelsByClient(ctx, session, clientID, pm)
|
||||
if err != nil {
|
||||
return cp, err
|
||||
}
|
||||
event := listChannelByClientEvent{
|
||||
clientID,
|
||||
pm,
|
||||
}
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return cp, err
|
||||
}
|
||||
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) EnableChannel(ctx context.Context, session authn.Session, id string) (channels.Channel, error) {
|
||||
cli, err := es.svc.EnableChannel(ctx, session, id)
|
||||
if err != nil {
|
||||
return cli, err
|
||||
}
|
||||
|
||||
return es.changeStatus(ctx, cli)
|
||||
}
|
||||
|
||||
func (es *eventStore) DisableChannel(ctx context.Context, session authn.Session, id string) (channels.Channel, error) {
|
||||
cli, err := es.svc.DisableChannel(ctx, session, id)
|
||||
if err != nil {
|
||||
return cli, err
|
||||
}
|
||||
|
||||
return es.changeStatus(ctx, cli)
|
||||
}
|
||||
|
||||
func (es *eventStore) changeStatus(ctx context.Context, ch channels.Channel) (channels.Channel, error) {
|
||||
event := changeStatusChannelEvent{
|
||||
id: ch.ID,
|
||||
updatedAt: ch.UpdatedAt,
|
||||
updatedBy: ch.UpdatedBy,
|
||||
status: ch.Status.String(),
|
||||
}
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return ch, err
|
||||
}
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) RemoveChannel(ctx context.Context, session authn.Session, id string) error {
|
||||
if err := es.svc.RemoveChannel(ctx, session, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := removeChannelEvent{id}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventStore) Connect(ctx context.Context, session authn.Session, chIDs, thIDs []string, connTypes []connections.ConnType) error {
|
||||
if err := es.svc.Connect(ctx, session, chIDs, thIDs, connTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := connectEvent{chIDs, thIDs, connTypes}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventStore) Disconnect(ctx context.Context, session authn.Session, chIDs, thIDs []string, connTypes []connections.ConnType) error {
|
||||
if err := es.svc.Disconnect(ctx, session, chIDs, thIDs, connTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := disconnectEvent{chIDs, thIDs, connTypes}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventStore) SetParentGroup(ctx context.Context, session authn.Session, parentGroupID string, id string) (err error) {
|
||||
if err := es.svc.SetParentGroup(ctx, session, parentGroupID, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := setParentGroupEvent{parentGroupID: parentGroupID, id: id}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventStore) RemoveParentGroup(ctx context.Context, session authn.Session, id string) (err error) {
|
||||
if err := es.svc.RemoveParentGroup(ctx, session, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := removeParentGroupEvent{id: id}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/authz"
|
||||
mgauthz "github.com/absmach/magistrala/pkg/authz"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/absmach/magistrala/pkg/policies"
|
||||
rmMW "github.com/absmach/magistrala/pkg/roles/rolemanager/middleware"
|
||||
"github.com/absmach/magistrala/pkg/svcutil"
|
||||
)
|
||||
|
||||
var (
|
||||
errView = errors.New("not authorized to view channel")
|
||||
errUpdate = errors.New("not authorized to update channel")
|
||||
errUpdateTags = errors.New("not authorized to update channel tags")
|
||||
errEnable = errors.New("not authorized to enable channel")
|
||||
errDisable = errors.New("not authorized to disable channel")
|
||||
errDelete = errors.New("not authorized to delete channel")
|
||||
errConnect = errors.New("not authorized to connect to channel")
|
||||
errDisconnect = errors.New("not authorized to disconnect from channel")
|
||||
errSetParentGroup = errors.New("not authorized to set parent group to channel")
|
||||
errRemoveParentGroup = errors.New("not authorized to remove parent group from channel")
|
||||
errDomainCreateChannels = errors.New("not authorized to create channel in domain")
|
||||
errGroupSetChildChannels = errors.New("not authorized to set child channel for group")
|
||||
errGroupRemoveChildChannels = errors.New("not authorized to remove child channel for group")
|
||||
errClientDisConnectChannels = errors.New("not authorized to disconnect channel for client")
|
||||
errClientConnectChannels = errors.New("not authorized to connect channel for client")
|
||||
)
|
||||
|
||||
var _ channels.Service = (*authorizationMiddleware)(nil)
|
||||
|
||||
type authorizationMiddleware struct {
|
||||
svc channels.Service
|
||||
repo channels.Repository
|
||||
authz mgauthz.Authorization
|
||||
opp svcutil.OperationPerm
|
||||
extOpp svcutil.ExternalOperationPerm
|
||||
rmMW.RoleManagerAuthorizationMiddleware
|
||||
}
|
||||
|
||||
// AuthorizationMiddleware adds authorization to the channels service.
|
||||
func AuthorizationMiddleware(svc channels.Service, repo channels.Repository, authz mgauthz.Authorization, channelsOpPerm, rolesOpPerm map[svcutil.Operation]svcutil.Permission, extOpPerm map[svcutil.ExternalOperation]svcutil.Permission) (channels.Service, error) {
|
||||
opp := channels.NewOperationPerm()
|
||||
if err := opp.AddOperationPermissionMap(channelsOpPerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := opp.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extOpp := channels.NewExternalOperationPerm()
|
||||
if err := extOpp.AddOperationPermissionMap(extOpPerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := extOpp.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ram, err := rmMW.NewRoleManagerAuthorizationMiddleware(policies.ChannelType, svc, authz, rolesOpPerm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &authorizationMiddleware{
|
||||
svc: svc,
|
||||
repo: repo,
|
||||
authz: authz,
|
||||
RoleManagerAuthorizationMiddleware: ram,
|
||||
opp: opp,
|
||||
extOpp: extOpp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) CreateChannels(ctx context.Context, session authn.Session, chs ...channels.Channel) ([]channels.Channel, error) {
|
||||
// If domain is disabled , then this authorization will fail for all non-admin domain users
|
||||
if err := am.extAuthorize(ctx, channels.DomainOpCreateChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.DomainType,
|
||||
Object: session.DomainID,
|
||||
}); err != nil {
|
||||
return []channels.Channel{}, errors.Wrap(err, errDomainCreateChannels)
|
||||
}
|
||||
|
||||
for _, ch := range chs {
|
||||
if ch.ParentGroup != "" {
|
||||
if err := am.extAuthorize(ctx, channels.GroupOpSetChildChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.GroupType,
|
||||
Object: ch.ParentGroup,
|
||||
}); err != nil {
|
||||
return []channels.Channel{}, errors.Wrap(err, errors.Wrap(errGroupSetChildChannels, fmt.Errorf("channel name %s parent group id %s", ch.Name, ch.ParentGroup)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return am.svc.CreateChannels(ctx, session, chs...)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) ViewChannel(ctx context.Context, session authn.Session, id string) (channels.Channel, error) {
|
||||
if err := am.authorize(ctx, channels.OpViewChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: id,
|
||||
}); err != nil {
|
||||
return channels.Channel{}, errors.Wrap(err, errView)
|
||||
}
|
||||
return am.svc.ViewChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) ListChannels(ctx context.Context, session authn.Session, pm channels.PageMetadata) (channels.Page, error) {
|
||||
if err := am.checkSuperAdmin(ctx, session.UserID); err != nil {
|
||||
session.SuperAdmin = true
|
||||
}
|
||||
return am.svc.ListChannels(ctx, session, pm)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) ListChannelsByClient(ctx context.Context, session authn.Session, clientID string, pm channels.PageMetadata) (channels.Page, error) {
|
||||
return am.svc.ListChannelsByClient(ctx, session, clientID, pm)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) UpdateChannel(ctx context.Context, session authn.Session, channel channels.Channel) (channels.Channel, error) {
|
||||
if err := am.authorize(ctx, channels.OpUpdateChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: channel.ID,
|
||||
}); err != nil {
|
||||
return channels.Channel{}, errors.Wrap(err, errUpdate)
|
||||
}
|
||||
return am.svc.UpdateChannel(ctx, session, channel)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) UpdateChannelTags(ctx context.Context, session authn.Session, channel channels.Channel) (channels.Channel, error) {
|
||||
if err := am.authorize(ctx, channels.OpUpdateChannelTags, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: channel.ID,
|
||||
}); err != nil {
|
||||
return channels.Channel{}, errors.Wrap(err, errUpdateTags)
|
||||
}
|
||||
return am.svc.UpdateChannelTags(ctx, session, channel)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) EnableChannel(ctx context.Context, session authn.Session, id string) (channels.Channel, error) {
|
||||
if err := am.authorize(ctx, channels.OpEnableChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: id,
|
||||
}); err != nil {
|
||||
return channels.Channel{}, errors.Wrap(err, errEnable)
|
||||
}
|
||||
return am.svc.EnableChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) DisableChannel(ctx context.Context, session authn.Session, id string) (channels.Channel, error) {
|
||||
if err := am.authorize(ctx, channels.OpDisableChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: id,
|
||||
}); err != nil {
|
||||
return channels.Channel{}, errors.Wrap(err, errDisable)
|
||||
}
|
||||
return am.svc.DisableChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) RemoveChannel(ctx context.Context, session authn.Session, id string) error {
|
||||
if err := am.authorize(ctx, channels.OpDeleteChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: id,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errDelete)
|
||||
}
|
||||
return am.svc.RemoveChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) Connect(ctx context.Context, session authn.Session, chIDs, thIDs []string, connTypes []connections.ConnType) error {
|
||||
for _, chID := range chIDs {
|
||||
if err := am.authorize(ctx, channels.OpConnectClient, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: chID,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errConnect)
|
||||
}
|
||||
}
|
||||
|
||||
for _, thID := range thIDs {
|
||||
if err := am.extAuthorize(ctx, channels.ClientsOpConnectChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ClientType,
|
||||
Object: thID,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errClientConnectChannels)
|
||||
}
|
||||
}
|
||||
return am.svc.Connect(ctx, session, chIDs, thIDs, connTypes)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) Disconnect(ctx context.Context, session authn.Session, chIDs, thIDs []string, connTypes []connections.ConnType) error {
|
||||
for _, chID := range chIDs {
|
||||
if err := am.authorize(ctx, channels.OpDisconnectClient, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: chID,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errDisconnect)
|
||||
}
|
||||
}
|
||||
|
||||
for _, thID := range thIDs {
|
||||
if err := am.extAuthorize(ctx, channels.ClientsOpDisconnectChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ClientType,
|
||||
Object: thID,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errClientDisConnectChannels)
|
||||
}
|
||||
}
|
||||
return am.svc.Disconnect(ctx, session, chIDs, thIDs, connTypes)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) SetParentGroup(ctx context.Context, session authn.Session, parentGroupID string, id string) error {
|
||||
if err := am.authorize(ctx, channels.OpSetParentGroup, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: id,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errSetParentGroup)
|
||||
}
|
||||
|
||||
if err := am.extAuthorize(ctx, channels.GroupOpSetChildChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.GroupType,
|
||||
Object: parentGroupID,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errGroupSetChildChannels)
|
||||
}
|
||||
return am.svc.SetParentGroup(ctx, session, parentGroupID, id)
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) RemoveParentGroup(ctx context.Context, session authn.Session, id string) error {
|
||||
if err := am.authorize(ctx, channels.OpSetParentGroup, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.ChannelType,
|
||||
Object: id,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errRemoveParentGroup)
|
||||
}
|
||||
|
||||
ch, err := am.repo.RetrieveByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
if ch.ParentGroup != "" {
|
||||
if err := am.extAuthorize(ctx, channels.GroupOpSetChildChannel, authz.PolicyReq{
|
||||
Domain: session.DomainID,
|
||||
SubjectType: policies.UserType,
|
||||
Subject: session.DomainUserID,
|
||||
ObjectType: policies.GroupType,
|
||||
Object: ch.ParentGroup,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, errGroupRemoveChildChannels)
|
||||
}
|
||||
return am.svc.RemoveParentGroup(ctx, session, id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) authorize(ctx context.Context, op svcutil.Operation, req authz.PolicyReq) error {
|
||||
perm, err := am.opp.GetPermission(op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Permission = perm.String()
|
||||
|
||||
if err := am.authz.Authorize(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) extAuthorize(ctx context.Context, extOp svcutil.ExternalOperation, req authz.PolicyReq) error {
|
||||
perm, err := am.extOpp.GetPermission(extOp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Permission = perm.String()
|
||||
|
||||
if err := am.authz.Authorize(ctx, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, userID string) error {
|
||||
if err := am.authz.Authorize(ctx, mgauthz.PolicyReq{
|
||||
SubjectType: policies.UserType,
|
||||
Subject: userID,
|
||||
Permission: policies.AdminPermission,
|
||||
ObjectType: policies.PlatformType,
|
||||
Object: policies.MagistralaObject,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
rmMW "github.com/absmach/magistrala/pkg/roles/rolemanager/middleware"
|
||||
)
|
||||
|
||||
var _ channels.Service = (*loggingMiddleware)(nil)
|
||||
|
||||
type loggingMiddleware struct {
|
||||
logger *slog.Logger
|
||||
svc channels.Service
|
||||
rmMW.RoleManagerLoggingMiddleware
|
||||
}
|
||||
|
||||
func LoggingMiddleware(svc channels.Service, logger *slog.Logger) channels.Service {
|
||||
return &loggingMiddleware{logger, svc, rmMW.NewRoleManagerLoggingMiddleware("channels", svc, logger)}
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) CreateChannels(ctx context.Context, session authn.Session, clients ...channels.Channel) (cs []channels.Channel, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn(fmt.Sprintf("Create %d channels failed", len(clients)), args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("Create %d channel completed successfully", len(clients)), args...)
|
||||
}(time.Now())
|
||||
return lm.svc.CreateChannels(ctx, session, clients...)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ViewChannel(ctx context.Context, session authn.Session, id string) (c channels.Channel, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("channel",
|
||||
slog.String("id", c.ID),
|
||||
slog.String("name", c.Name),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("View channel failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("View channel completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.ViewChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListChannels(ctx context.Context, session authn.Session, pm channels.PageMetadata) (cp channels.Page, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("page",
|
||||
slog.Uint64("limit", pm.Limit),
|
||||
slog.Uint64("offset", pm.Offset),
|
||||
slog.Uint64("total", cp.Total),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("List channels failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("List channels completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.ListChannels(ctx, session, pm)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListChannelsByClient(ctx context.Context, session authn.Session, clientID string, pm channels.PageMetadata) (cp channels.Page, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("client_id", clientID),
|
||||
slog.Group("page",
|
||||
slog.Uint64("limit", pm.Limit),
|
||||
slog.Uint64("offset", pm.Offset),
|
||||
slog.Uint64("total", cp.Total),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("List channels by client failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("List channels by client completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.ListChannelsByClient(ctx, session, clientID, pm)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UpdateChannel(ctx context.Context, session authn.Session, client channels.Channel) (c channels.Channel, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("channel",
|
||||
slog.String("id", client.ID),
|
||||
slog.String("name", client.Name),
|
||||
slog.Any("metadata", client.Metadata),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Update channel failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Update channel completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.UpdateChannel(ctx, session, client)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UpdateChannelTags(ctx context.Context, session authn.Session, client channels.Channel) (c channels.Channel, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("channel",
|
||||
slog.String("id", c.ID),
|
||||
slog.String("name", c.Name),
|
||||
slog.Any("tags", c.Tags),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args := append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Update channel tags failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Update channel tags completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.UpdateChannelTags(ctx, session, client)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) EnableChannel(ctx context.Context, session authn.Session, id string) (c channels.Channel, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("channel",
|
||||
slog.String("id", id),
|
||||
slog.String("name", c.Name),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Enable channel failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Enable channel completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.EnableChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) DisableChannel(ctx context.Context, session authn.Session, id string) (c channels.Channel, err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("channel",
|
||||
slog.String("id", id),
|
||||
slog.String("name", c.Name),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Disable channel failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Disable channel completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.DisableChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RemoveChannel(ctx context.Context, session authn.Session, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("channel_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Delete channel failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Delete channel completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.RemoveChannel(ctx, session, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Connect(ctx context.Context, session authn.Session, chIDs, clIDs []string, connTypes []connections.ConnType) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Any("channel_ids", chIDs),
|
||||
slog.Any("client_ids", clIDs),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Connect channels and clients failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Connect channels and clients completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.Connect(ctx, session, chIDs, clIDs, connTypes)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Disconnect(ctx context.Context, session authn.Session, chIDs, clIDs []string, connTypes []connections.ConnType) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Any("channel_ids", chIDs),
|
||||
slog.Any("client_ids", clIDs),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Disconnect channels and clients failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Disconnect channels and clients completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.Disconnect(ctx, session, chIDs, clIDs, connTypes)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) SetParentGroup(ctx context.Context, session authn.Session, parentGroupID string, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("parent_group_id", parentGroupID),
|
||||
slog.String("channel_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Set parent group to channel failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Set parent group to channel completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.SetParentGroup(ctx, session, parentGroupID, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) RemoveParentGroup(ctx context.Context, session authn.Session, id string) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.String("channel_id", id),
|
||||
}
|
||||
if err != nil {
|
||||
args = append(args, slog.String("error", err.Error()))
|
||||
lm.logger.Warn("Remove parent group from channel failed", args...)
|
||||
return
|
||||
}
|
||||
lm.logger.Info("Remove parent group from channel completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.RemoveParentGroup(ctx, session, id)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user