keycloak-admin 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/Dockerfile +24 -0
  3. data/.github/workflows/ci.yml +83 -0
  4. data/CHANGELOG.md +5 -0
  5. data/Gemfile.lock +3 -3
  6. data/README.md +267 -1
  7. data/lib/keycloak-admin/client/client_authz_permission_client.rb +81 -0
  8. data/lib/keycloak-admin/client/client_authz_policy_client.rb +76 -0
  9. data/lib/keycloak-admin/client/client_authz_resource_client.rb +93 -0
  10. data/lib/keycloak-admin/client/client_authz_scope_client.rb +71 -0
  11. data/lib/keycloak-admin/client/realm_client.rb +16 -0
  12. data/lib/keycloak-admin/representation/client_authz_permission_representation.rb +34 -0
  13. data/lib/keycloak-admin/representation/client_authz_policy_config_representation.rb +15 -0
  14. data/lib/keycloak-admin/representation/client_authz_policy_representation.rb +27 -0
  15. data/lib/keycloak-admin/representation/client_authz_resource_representation.rb +26 -0
  16. data/lib/keycloak-admin/representation/client_authz_scope_representation.rb +17 -0
  17. data/lib/keycloak-admin/version.rb +1 -1
  18. data/lib/keycloak-admin.rb +9 -0
  19. data/spec/client/client_authz_permission_client_spec.rb +170 -0
  20. data/spec/client/client_authz_policy_client_spec.rb +170 -0
  21. data/spec/client/client_authz_resource_client_spec.rb +150 -0
  22. data/spec/client/client_authz_scope_client_spec.rb +134 -0
  23. data/spec/integration/client_authorization_spec.rb +95 -0
  24. data/spec/representation/client_authz_permission_representation_spec.rb +52 -0
  25. data/spec/representation/client_authz_policy_representation_spec.rb +47 -0
  26. data/spec/representation/client_authz_resource_representation_spec.rb +33 -0
  27. data/spec/representation/client_authz_scope_representation_spec.rb +19 -0
  28. metadata +23 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75a9e29c443612983e789a4d2d38d050908a0239fd4b74bca5f5d722234ef940
4
- data.tar.gz: e0bf740884bb1da5bf3c63032f6349e46f98ce56f1b06f0ae62dcb96eb324bb7
3
+ metadata.gz: be47369f8365b8b32ff4ca3b09ebad45f5037212eca3022524b10ba17b0f64d6
4
+ data.tar.gz: 36a340f437ecb97ce5c415e752d5e1159ebbc5911d454f643985de541c6deaf3
5
5
  SHA512:
6
- metadata.gz: 1cc1adf071a240af23ace33f0f48d3b4c9cee0868dc4e50acab30d900bc0575fd4784bd725869dff58e79c053e4b6505376569855fbdb647bf929b8d82190277
7
- data.tar.gz: e34ae74e3096db9fa6ac6c92370eed71e23e25a4d896a98eed1afb68cfeb422d66ad99eb5d4a02460bd7fa3a6b57b2c6b351bfb42d4adb7fcdab70fc838f4825
6
+ metadata.gz: 6bd85e4709a0044168b7c3b3e9e2d89b1fab559070d4a318d65283db2046716439c4d1d0a534ba3cc9b1cbc89771626945877a76723bd03cc5f0e6dbebe6b266
7
+ data.tar.gz: e4b2286bac6d7e11192a1f3b6a569170849275bd3fa91aa104cdf521139a691396c8681a4152b5611e6a28e6c1457f60329b39ebca44cc4eb328f9ade9f7f605
@@ -0,0 +1,24 @@
1
+ ### Dockerfile for: tillawy/keycloak-github-actions
2
+ ##
3
+ ## To build & push
4
+ # docker buildx build . --platform linux/amd64 -t tillawy/keycloak-github-actions:25.0.1
5
+ # docker push tillawy/keycloak-github-actions:25.0.1
6
+ #
7
+ ## To Run Locally
8
+ # docker run \
9
+ # --rm \
10
+ # -p 8080:8080 \
11
+ # -e KEYCLOAK_ADMIN="admin" \
12
+ # -e KEYCLOAK_ADMIN_PASSWORD="admin" \
13
+ # -e KC_HOSTNAME="http://localhost:8080" \
14
+ # -e KC_HOSTNAME_ADMIN="http://localhost:8080" \
15
+ # -e KC_HTTP_ENABLED="true" \
16
+ # -e KC_DB="dev-file" \
17
+ # tillawy/keycloak-github-actions:25.0.1
18
+
19
+ FROM quay.io/keycloak/keycloak:25.0.1
20
+
21
+ ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
22
+
23
+ CMD ["start-dev", "--hostname=http://localhost:8080" , "--hostname-admin=http://localhost:8080" , "--http-enabled=true", "--verbose"]
24
+
@@ -0,0 +1,83 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ "main" ]
13
+ pull_request:
14
+ branches: [ "main" ]
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+ runs-on: ubuntu-latest
22
+ services:
23
+ keycloak:
24
+ image: tillawy/keycloak-github-actions:25.0.1
25
+ ports:
26
+ - 8080:8080
27
+ options: '--health-cmd "exec 3<>/dev/tcp/localhost/8080" --health-interval 5s --health-timeout 5s --health-retries 10 --health-start-period 100s'
28
+ env:
29
+ KEYCLOAK_ADMIN: "admin"
30
+ KEYCLOAK_ADMIN_PASSWORD: "admin"
31
+ KC_HOSTNAME: "http://localhost:8080"
32
+ KC_HOSTNAME_ADMIN: "http://localhost:8080"
33
+ KC_HTTP_ENABLED: "true"
34
+ KC_DB: "dev-file"
35
+
36
+ strategy:
37
+ matrix:
38
+ ruby-version: ['3.2']
39
+
40
+ steps:
41
+ - name: create realm
42
+ run: |
43
+ TOKEN=$(curl --silent --location --request POST "http://localhost:8080/realms/master/protocol/openid-connect/token" \
44
+ --header 'Content-Type: application/x-www-form-urlencoded' \
45
+ --data-urlencode 'grant_type=password' \
46
+ --data-urlencode 'username=admin' \
47
+ --data-urlencode 'password=admin' \
48
+ --data-urlencode 'client_id=admin-cli' | jq -r '.access_token')
49
+
50
+ curl --silent --show-error -L -X POST "http://localhost:8080/admin/realms" \
51
+ --header "Content-Type: application/json" \
52
+ --header "Authorization: Bearer ${TOKEN}" \
53
+ --data '{"realm":"dummy","enabled":true}'
54
+
55
+ curl --silent --show-error --request POST 'http://localhost:8080/admin/realms/dummy/clients' \
56
+ --header 'Authorization: Bearer '$TOKEN \
57
+ --header 'Content-Type: application/json' \
58
+ --data-raw '{
59
+ "clientId":"dummy-client",
60
+ "enabled":true,
61
+ "consentRequired": false,
62
+ "attributes":{},
63
+ "serviceAccountsEnabled": true,
64
+ "protocol":"openid-connect",
65
+ "publicClient":false,
66
+ "authorizationServicesEnabled": true,
67
+ "clientAuthenticatorType":"client-secret",
68
+ "redirectUris":["http://localhost:8180/demo"]
69
+ }'
70
+
71
+ - uses: actions/checkout@v4
72
+ - name: Set up Ruby
73
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
74
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
75
+ # uses: ruby/setup-ruby@v1
76
+ uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
77
+ with:
78
+ ruby-version: ${{ matrix.ruby-version }}
79
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
80
+ - name: Run tests
81
+ run: bundle exec rspec
82
+ env:
83
+ GITHUB_ACTIONS: true
data/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.3] - 2024-07-12
9
+
10
+ * Client Authorization management support (thanks to @tillawy)
11
+ * GitHub-actions setup to execute `rspec` (thanks to @tillawy)
12
+
8
13
  ## [1.1.2] - 2024-05-22
9
14
 
10
15
  * Add group endpoints (get, children, delete), support for group attributes (thanks to @mkrawc)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- keycloak-admin (1.1.2)
4
+ keycloak-admin (1.1.3)
5
5
  http-cookie (~> 1.0, >= 1.0.3)
6
6
  rest-client (~> 2.0)
7
7
 
@@ -12,11 +12,11 @@ GEM
12
12
  diff-lcs (1.5.1)
13
13
  domain_name (0.6.20240107)
14
14
  http-accept (1.7.0)
15
- http-cookie (1.0.5)
15
+ http-cookie (1.0.6)
16
16
  domain_name (~> 0.5)
17
17
  mime-types (3.5.2)
18
18
  mime-types-data (~> 3.2015)
19
- mime-types-data (3.2024.0507)
19
+ mime-types-data (3.2024.0702)
20
20
  netrc (0.11.0)
21
21
  rest-client (2.1.0)
22
22
  http-accept (>= 1.7.0, < 2.0)
data/README.md CHANGED
@@ -12,7 +12,7 @@ This gem *does not* require Rails.
12
12
  For example, using `bundle`, add this line to your Gemfile.
13
13
 
14
14
  ```ruby
15
- gem "keycloak-admin", "1.1.2"
15
+ gem "keycloak-admin", "1.1.3"
16
16
  ```
17
17
 
18
18
  ## Login
@@ -133,6 +133,7 @@ All options have a default value. However, all of them can be changed in your in
133
133
  * Link/Unlink users to federated identity provider brokers
134
134
  * Execute actions emails
135
135
  * Send forgot passsword mail
136
+ * Client Authorization, create, update, get, delete Resource, Scope, Policy, Permission, Policy Enforcer
136
137
 
137
138
  ### Get an access token
138
139
 
@@ -472,6 +473,271 @@ Returns an array of `KeycloakAdmin::IdentityProviderRepresentation`.
472
473
  KeycloakAdmin.realm("a_realm").identity_providers.list
473
474
  ```
474
475
 
476
+ ### Manage [Client Authorization Resources & Scopes](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_overview)
477
+
478
+ In order to use authorization, you need to enable the client's `authorization_services_enabled` attribute.
479
+
480
+ ```ruby
481
+ client_id = "dummy-client"
482
+ client = KeycloakAdmin.realm("realm_a").clients.find_by_client_id(client_id)
483
+ client.authorization_services_enabled = true
484
+ KeycloakAdmin.realm("a_realm").clients.update(client)
485
+ ```
486
+
487
+ ### Create a scope
488
+
489
+ Returns added `KeycloakAdmin::ClientAuthzScopeRepresentation`
490
+
491
+ ```ruby
492
+ KeycloakAdmin.realm("a_realm").authz_scopes(client_id).create!("POST_1", "POST 1 scope description", "http://icon.url")
493
+ ````
494
+
495
+ ### Search for scope
496
+
497
+ Returns array of `KeycloakAdmin::ClientAuthzScopeRepresentation`
498
+
499
+ ```ruby
500
+ KeycloakAdmin.realm("a_realm").authz_scopes(client.id).search("POST")
501
+ ```
502
+
503
+ ### Get one scope by its id
504
+
505
+ Returns `KeycloakAdmin::ClientAuthzScopeRepresentation`
506
+
507
+ ```ruby
508
+ KeycloakAdmin.realm("a_realm").authz_scopes(client.id).get(scope_id)
509
+ ```
510
+
511
+ ### Delete one scope
512
+
513
+ ```ruby
514
+ KeycloakAdmin.realm("a_realm").authz_scopes(client.id).delete(scope.id)
515
+ ```
516
+
517
+ ### Create a client authorization resource
518
+
519
+ note: for scopes, use {name: scope.name} to reference the scope object
520
+
521
+ Returns added `KeycloakAdmin::ClientAuthzResourceRepresentation`
522
+
523
+ ```ruby
524
+ KeycloakAdmin.realm("realm_id")
525
+ .authz_resources(client.id)
526
+ .create!(
527
+ "Dummy Resource",
528
+ "type",
529
+ ["/resource_1/*", "/resource_1/"],
530
+ true,
531
+ "display_name",
532
+ [ {name: scope_1.name} ],
533
+ {"attribute": ["value_1", "value_2"]}
534
+ )
535
+ ```
536
+
537
+ ### Update a client authorization resource
538
+
539
+ Returns updated `KeycloakAdmin::ClientAuthzResourceRepresentation`
540
+
541
+ note: for scopes, use {name: scope.name} to reference the scope object
542
+
543
+ ```ruby
544
+ KeycloakAdmin.realm("realm_a")
545
+ .authz_resources(client.id)
546
+ .update(resource.id,
547
+ {
548
+ "name": "Dummy Resource",
549
+ "type": "type",
550
+ "owner_managed_access": true,
551
+ "display_name": "display_name",
552
+ "attributes": {"a":["b","c"]},
553
+ "uris": [ "/resource_1/*" , "/resource_1/" ],
554
+ "scopes":[
555
+ {name: scope_1.name},
556
+ {name: scope_2.name}
557
+ ],
558
+ "icon_uri": "https://icon.url"
559
+ })
560
+ ```
561
+
562
+ ### Find client authorization resources by (name, type, uri, owner, scope)
563
+
564
+ Returns array of `KeycloakAdmin::ClientAuthzResourceRepresentation`
565
+
566
+ ```ruby
567
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).find_by("Dummy Resource", "", "", "", "")
568
+ ```
569
+ or
570
+ ```ruby
571
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).find_by("", "type", "", "", "")
572
+ ```
573
+
574
+ ### Get client authorization resource by its id
575
+
576
+ Returns `KeycloakAdmin::ClientAuthzResourceRepresentation`
577
+
578
+ ```ruby
579
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).get(resource.id)
580
+ ```
581
+
582
+ ### delete a client authorization resource
583
+
584
+ ```ruby
585
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).delete(resource.id)
586
+ ```
587
+
588
+ ### Create a client authorization policy
589
+
590
+ Note: for the moment only `role` policies are supported.
591
+
592
+ Returns added `KeycloakAdmin::ClientAuthzPolicyRepresentation`
593
+
594
+ ```ruby
595
+ KeycloakAdmin.realm("realm_a")
596
+ .authz_policies(client.id, 'role')
597
+ .create!("Policy 1",
598
+ "description",
599
+ "role",
600
+ "POSITIVE",
601
+ "UNANIMOUS",
602
+ true,
603
+ [{id: realm_role.id, required: true}]
604
+ )
605
+ ```
606
+
607
+ ### Find client authorization policies by (name, type)
608
+
609
+ Returns array of `KeycloakAdmin::ClientAuthzPolicyRepresentation`
610
+
611
+ ```ruby
612
+ KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').find_by("Policy 1", "role")
613
+ ```
614
+
615
+ ### Get client authorization policy by its id
616
+
617
+ Returns `KeycloakAdmin::ClientAuthzPolicyRepresentation`
618
+
619
+ ```ruby
620
+ KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').get(policy.id)
621
+ ```
622
+
623
+ ### Delete a client authorization policy
624
+
625
+ ```ruby
626
+ KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').delete(policy.id)
627
+ ```
628
+
629
+ ### Create a client authorization permission (Resource type)
630
+
631
+ Returns added `KeycloakAdmin::ClientAuthzPermissionRepresentation`
632
+
633
+ ```ruby
634
+ KeycloakAdmin.realm("realm_a")
635
+ .authz_permissions(client.id, :resource)
636
+ .create!("Dummy Resource Permission",
637
+ "resource description",
638
+ "UNANIMOUS",
639
+ "POSITIVE",
640
+ [resource.id],
641
+ [policy.id],
642
+ nil,
643
+ ""
644
+ )
645
+ ```
646
+
647
+ ### Create a client authorization permission (Scope type)
648
+
649
+ Returns added `KeycloakAdmin::ClientAuthzPermissionRepresentation`
650
+
651
+ ```ruby
652
+ KeycloakAdmin.realm("realm_a")
653
+ .authz_permissions(client.id, :scope)
654
+ .create!("Dummy Scope Permission",
655
+ "scope description",
656
+ "UNANIMOUS",
657
+ "POSITIVE",
658
+ [resource.id],
659
+ [policy.id],
660
+ [scope_1.id, scope_2.id],
661
+ ""
662
+ )
663
+ ```
664
+
665
+ ### List a resource authorization permissions (all: scope or resource)
666
+
667
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
668
+
669
+ ```ruby
670
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "", resource.id).list
671
+ ```
672
+
673
+ ### List a resource authorization permissions (by type: resource)
674
+
675
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
676
+
677
+ ```ruby
678
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'resource').list
679
+ ```
680
+ ### List a resource authorization permissions (by type: scope)
681
+
682
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
683
+
684
+ ```ruby
685
+ authz_permissions(client.id, 'scope').list.size
686
+ ```
687
+
688
+ ### Find client authorization permissions by (name, type, scope)
689
+
690
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
691
+
692
+ ```ruby
693
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, nil)
694
+ ```
695
+ or
696
+ ```ruby
697
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, nil)
698
+ ```
699
+ or
700
+ ```ruby
701
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, resource.id)
702
+
703
+ ```
704
+ or
705
+ ```ruby
706
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, resource.id)
707
+ ```
708
+ or
709
+ ```ruby
710
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, resource.id, "POST_1")
711
+ ```
712
+ or
713
+ ```ruby
714
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(nil, resource.id)
715
+ ```
716
+ or
717
+ ```ruby
718
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(nil, resource.id)
719
+ ```
720
+ or
721
+ ```ruby
722
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(nil, resource.id, "POST_1")
723
+ ```
724
+ or
725
+ ```ruby
726
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, nil)
727
+ ```
728
+
729
+ ### Delete a client authorization permission, scope type
730
+
731
+ ```ruby
732
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'scope').delete(scope.id)
733
+ ```
734
+
735
+ ### Delete a client authorization permission, resource type
736
+
737
+ ```ruby
738
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'resource').delete(resource_permission.id)
739
+ ```
740
+
475
741
  ## How to execute library tests
476
742
 
477
743
  From the `keycloak-admin-api` directory:
@@ -0,0 +1,81 @@
1
+ module KeycloakAdmin
2
+ class ClientAuthzPermissionClient < Client
3
+ def initialize(configuration, realm_client, client_id, type, resource_id = nil)
4
+ super(configuration)
5
+ raise ArgumentError.new("realm must be defined") unless realm_client.name_defined?
6
+ raise ArgumentError.new("bad permission type") if !resource_id && !%i[resource scope].include?(type.to_sym)
7
+
8
+ @realm_client = realm_client
9
+ @client_id = client_id
10
+ @type = type
11
+ @resource_id = resource_id
12
+ end
13
+
14
+ def delete(permission_id)
15
+ execute_http do
16
+ RestClient::Resource.new(authz_permission_url(@client_id, nil, nil, permission_id), @configuration.rest_client_options).delete(headers)
17
+ end
18
+ true
19
+ end
20
+
21
+ def find_by(name, resource, scope = nil)
22
+ response = execute_http do
23
+ url = "#{authz_permission_url(@client_id)}?name=#{name}&resource=#{resource}&type=#{@type}&scope=#{scope}&deep=true&first=0&max=100"
24
+ RestClient::Resource.new(url, @configuration.rest_client_options).get(headers)
25
+ end
26
+ JSON.parse(response).map { |role_as_hash| ClientAuthzPermissionRepresentation.from_hash(role_as_hash) }
27
+ end
28
+
29
+ def create!(name, description, decision_strategy,logic = "POSITIVE", resources = [], policies = [], scopes = [], resource_type = nil)
30
+ response = save(build(name, description, decision_strategy, logic, resources, policies, scopes, resource_type))
31
+ ClientAuthzPermissionRepresentation.from_hash(JSON.parse(response))
32
+ end
33
+
34
+ def save(permission_representation)
35
+ execute_http do
36
+ RestClient::Resource.new(authz_permission_url(@client_id, nil, permission_representation.type), @configuration.rest_client_options).post(
37
+ create_payload(permission_representation), headers
38
+ )
39
+ end
40
+ end
41
+
42
+ def list
43
+ response = execute_http do
44
+ RestClient::Resource.new(authz_permission_url(@client_id, @resource_id), @configuration.rest_client_options).get(headers)
45
+ end
46
+ JSON.parse(response).map { |role_as_hash| ClientAuthzPermissionRepresentation.from_hash(role_as_hash) }
47
+ end
48
+
49
+ def get(permission_id)
50
+ response = execute_http do
51
+ RestClient::Resource.new(authz_permission_url(@client_id, nil, @type, permission_id), @configuration.rest_client_options).get(headers)
52
+ end
53
+ ClientAuthzPermissionRepresentation.from_hash(JSON.parse(response))
54
+ end
55
+
56
+ def authz_permission_url(client_id, resource_id = nil, type = nil, id = nil)
57
+ if resource_id
58
+ "#{@realm_client.realm_admin_url}/clients/#{client_id}/authz/resource-server/resource/#{resource_id}/permissions"
59
+ elsif id
60
+ "#{@realm_client.realm_admin_url}/clients/#{client_id}/authz/resource-server/permission/#{type}/#{id}"
61
+ else
62
+ "#{@realm_client.realm_admin_url}/clients/#{client_id}/authz/resource-server/permission/#{type}"
63
+ end
64
+ end
65
+
66
+ def build(name, description, decision_strategy, logic, resources, policies, scopes, resource_type)
67
+ policy = ClientAuthzPermissionRepresentation.new
68
+ policy.name = name
69
+ policy.description = description
70
+ policy.type = @type
71
+ policy.decision_strategy = decision_strategy
72
+ policy.resource_type = resource_type
73
+ policy.resources = resources
74
+ policy.policies = policies
75
+ policy.scopes = scopes
76
+ policy.logic = logic
77
+ policy
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,76 @@
1
+ module KeycloakAdmin
2
+ class ClientAuthzPolicyClient < Client
3
+ def initialize(configuration, realm_client, client_id, type)
4
+ super(configuration)
5
+ raise ArgumentError.new("realm must be defined") unless realm_client.name_defined?
6
+ raise ArgumentError.new("type must be defined") unless type
7
+ raise ArgumentError.new("only 'role' policies supported") unless type.to_sym == :role
8
+
9
+ @realm_client = realm_client
10
+ @client_id = client_id
11
+ @type = type
12
+ end
13
+
14
+ def create!(name, description, type, logic, decision_strategy, fetch_roles, roles)
15
+ response = save(build(name, description, type, logic, decision_strategy, fetch_roles, roles))
16
+ ClientAuthzPolicyRepresentation.from_hash(JSON.parse(response))
17
+ end
18
+
19
+ def save(policy_representation)
20
+ execute_http do
21
+ RestClient::Resource.new(authz_policy_url(@client_id, @type), @configuration.rest_client_options).post(
22
+ create_payload(policy_representation), headers
23
+ )
24
+ end
25
+ end
26
+
27
+ def get(policy_id)
28
+ response = execute_http do
29
+ RestClient::Resource.new(authz_policy_url(@client_id, @type, policy_id), @configuration.rest_client_options).get(headers)
30
+ end
31
+ ClientAuthzPolicyRepresentation.from_hash(JSON.parse(response))
32
+ end
33
+
34
+ def find_by(name, type)
35
+ response = execute_http do
36
+ url = "#{authz_policy_url(@client_id, @type)}?permission=false&name=#{name}&type=#{type}&first=0&max=11"
37
+ RestClient::Resource.new(url, @configuration.rest_client_options).get(headers)
38
+ end
39
+ JSON.parse(response).map { |role_as_hash| ClientAuthzPolicyRepresentation.from_hash(role_as_hash) }
40
+ end
41
+
42
+ def delete(policy_id)
43
+ execute_http do
44
+ RestClient::Resource.new(authz_policy_url(@client_id, @type, policy_id), @configuration.rest_client_options).delete(headers)
45
+ end
46
+ true
47
+ end
48
+
49
+ def list
50
+ response = execute_http do
51
+ RestClient::Resource.new(authz_policy_url(@client_id, @type), @configuration.rest_client_options).get(headers)
52
+ end
53
+ JSON.parse(response).map { |role_as_hash| ClientAuthzPolicyRepresentation.from_hash(role_as_hash) }
54
+ end
55
+
56
+ def authz_policy_url(client_id, type, id = nil)
57
+ if id
58
+ "#{@realm_client.realm_admin_url}/clients/#{client_id}/authz/resource-server/policy/#{type}/#{id}"
59
+ else
60
+ "#{@realm_client.realm_admin_url}/clients/#{client_id}/authz/resource-server/policy/#{type}?permission=false"
61
+ end
62
+ end
63
+
64
+ def build(name, description, type, logic, decision_strategy, fetch_roles, roles=[])
65
+ policy = ClientAuthzPolicyRepresentation.new
66
+ policy.name = name
67
+ policy.description = description
68
+ policy.type = type
69
+ policy.logic = logic
70
+ policy.decision_strategy = decision_strategy
71
+ policy.fetch_roles = fetch_roles
72
+ policy.roles = roles
73
+ policy
74
+ end
75
+ end
76
+ end