keycloak-admin 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
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