casdoor-ruby-sdk 1.0.0 → 1.1.1
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.
- checksums.yaml +4 -4
- data/README.md +134 -55
- data/lib/casdoor/adapter.rb +48 -0
- data/lib/casdoor/application.rb +48 -0
- data/lib/casdoor/auth.rb +143 -0
- data/lib/casdoor/cert.rb +47 -0
- data/lib/casdoor/email.rb +33 -0
- data/lib/casdoor/enforce.rb +47 -0
- data/lib/casdoor/enforcer.rb +48 -0
- data/lib/casdoor/entity.rb +17 -44
- data/lib/casdoor/global.rb +34 -0
- data/lib/casdoor/group.rb +48 -0
- data/lib/casdoor/invitation.rb +57 -0
- data/lib/casdoor/jwt.rb +75 -0
- data/lib/casdoor/ldap.rb +67 -0
- data/lib/casdoor/logout.rb +41 -0
- data/lib/casdoor/mfa.rb +53 -0
- data/lib/casdoor/model.rb +48 -0
- data/lib/casdoor/notification.rb +29 -0
- data/lib/casdoor/order.rb +59 -0
- data/lib/casdoor/order_pay.rb +40 -0
- data/lib/casdoor/organization.rb +47 -0
- data/lib/casdoor/payment.rb +61 -0
- data/lib/casdoor/permission.rb +57 -0
- data/lib/casdoor/plan.rb +48 -0
- data/lib/casdoor/policy.rb +67 -0
- data/lib/casdoor/pricing.rb +48 -0
- data/lib/casdoor/product.rb +48 -0
- data/lib/casdoor/provider.rb +48 -0
- data/lib/casdoor/record.rb +43 -0
- data/lib/casdoor/resource.rb +75 -0
- data/lib/casdoor/role.rb +52 -0
- data/lib/casdoor/session.rb +53 -0
- data/lib/casdoor/sms.rb +31 -0
- data/lib/casdoor/subscription.rb +48 -0
- data/lib/casdoor/syncer.rb +48 -0
- data/lib/casdoor/token.rb +60 -0
- data/lib/casdoor/transaction.rb +62 -0
- data/lib/casdoor/url.rb +47 -0
- data/lib/casdoor/user.rb +124 -0
- data/lib/casdoor/util.rb +147 -0
- data/lib/casdoor/util_modify.rb +65 -0
- data/lib/casdoor/version.rb +1 -1
- data/lib/casdoor/webhook.rb +48 -0
- data/lib/casdoor.rb +13 -5
- metadata +41 -6
- data/lib/casdoor/api/auth.rb +0 -153
- data/lib/casdoor/api/crud.rb +0 -122
- data/lib/casdoor/api/enforce.rb +0 -44
- data/lib/casdoor/api/users.rb +0 -83
- data/lib/casdoor/client.rb +0 -143
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c7442875c53f487dff6e4968e27e7aec47b23a2143799305b7c324ca32594479
|
|
4
|
+
data.tar.gz: 3fb25488582dc9fa39ee6ad226eab7514bc23ced81f946b3562a7e5fa9b5fb4d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de59e3233811816621ad27f50b3d8639e780f8ce1fbf50ca9e361e466f9458eb1ec455a990991ca7ed1af6f181331c1572583cb1df658fc6bee43020b01f2e15
|
|
7
|
+
data.tar.gz: bc47f66464a2f7d9206e97437c8babb9aa99ea2a13e70c2798de0fdf701f1434f3ebdcb76f7985d2707872d443148dc0704ba557d1613f0775a1ec571017132e
|
data/README.md
CHANGED
|
@@ -9,9 +9,13 @@
|
|
|
9
9
|
[](https://discord.gg/5rPsrAzK7S)
|
|
10
10
|
|
|
11
11
|
The Ruby SDK of [Casdoor](https://casdoor.ai/). It lets a Ruby application (Rails, Sinatra, Hanami, ...) sign users in
|
|
12
|
-
with Casdoor, verify the tokens issued by Casdoor, and manage the users, applications, roles, permissions and the
|
|
12
|
+
with Casdoor, verify the tokens issued by Casdoor, and manage the users, applications, roles, permissions and all the
|
|
13
13
|
other objects of Casdoor through its API.
|
|
14
14
|
|
|
15
|
+
It has the same APIs as the [Go SDK](https://github.com/casdoor/casdoor-go-sdk), in snake_case: `GetUsers()` is
|
|
16
|
+
`get_users`, `UpdateUserForColumns(user, columns)` is `update_user_for_columns(user, columns)`, and so on. The files
|
|
17
|
+
under `lib/casdoor/` match the files of the Go SDK's `casdoorsdk` package.
|
|
18
|
+
|
|
15
19
|
## Installation
|
|
16
20
|
|
|
17
21
|
Add it to the `Gemfile`:
|
|
@@ -26,23 +30,36 @@ It requires Ruby 2.7 or later, and depends only on the [jwt](https://github.com/
|
|
|
26
30
|
|
|
27
31
|
## Configuration
|
|
28
32
|
|
|
33
|
+
| Name | Must | Description |
|
|
34
|
+
|-------------------|------|-------------------------------------------------------------------------------------|
|
|
35
|
+
| endpoint | Yes | The URL of Casdoor, such as `https://door.casdoor.com` |
|
|
36
|
+
| client_id | Yes | The "Client ID" of the application |
|
|
37
|
+
| client_secret | Yes | The "Client secret" of the application |
|
|
38
|
+
| certificate | No | The "Certificate" of the application's cert (PEM), only needed to verify JWT tokens |
|
|
39
|
+
| organization_name | Yes | The organization of the users |
|
|
40
|
+
| application_name | Yes | The name of the application |
|
|
41
|
+
|
|
42
|
+
Like the Go SDK, either create a client:
|
|
43
|
+
|
|
29
44
|
```ruby
|
|
30
45
|
require 'casdoor'
|
|
31
46
|
|
|
32
|
-
client = Casdoor
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
47
|
+
client = Casdoor.new_client(endpoint, client_id, client_secret, certificate, organization_name, application_name)
|
|
48
|
+
users = client.get_users
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
or initialize the global client, then call the APIs on the `Casdoor` module:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
Casdoor.init_config(endpoint, client_id, client_secret, certificate, organization_name, application_name)
|
|
55
|
+
users = Casdoor.get_users
|
|
40
56
|
```
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
58
|
+
`Casdoor::Client.new` takes the same settings as keyword arguments, plus `custom_headers:` (added to every request),
|
|
59
|
+
`open_timeout:` and `read_timeout:`.
|
|
44
60
|
|
|
45
|
-
|
|
61
|
+
The certificate is shown on the edit page of the cert that the application uses ("Certs" → the application's cert →
|
|
62
|
+
"Certificate"). A public key in PEM format works too.
|
|
46
63
|
|
|
47
64
|
## Signing users in
|
|
48
65
|
|
|
@@ -54,14 +71,13 @@ redirect_to client.get_signin_url('https://your-app.example.com/callback', state
|
|
|
54
71
|
|
|
55
72
|
# 2. Casdoor redirects back to the callback with "code" and "state", exchange the code for the tokens
|
|
56
73
|
raise 'Invalid state' unless params[:state] == session[:state]
|
|
57
|
-
token = client.get_oauth_token(params[:code])
|
|
74
|
+
token = client.get_oauth_token(params[:code], params[:state])
|
|
58
75
|
# => {"access_token" => "...", "id_token" => "...", "refresh_token" => "...", "expires_in" => 604800, ...}
|
|
59
76
|
|
|
60
77
|
# 3. Verify the access token and read the user in it
|
|
61
78
|
claims = client.parse_jwt_token(token['access_token'])
|
|
62
79
|
claims.name # => "alice"
|
|
63
80
|
claims.owner # => "casbin", the organization
|
|
64
|
-
claims.email
|
|
65
81
|
claims.user # => Casdoor::User with the fields of the user
|
|
66
82
|
```
|
|
67
83
|
|
|
@@ -71,20 +87,21 @@ this application (its client ID); otherwise it raises `Casdoor::InvalidTokenErro
|
|
|
71
87
|
Other helpers:
|
|
72
88
|
|
|
73
89
|
```ruby
|
|
74
|
-
client.get_signup_url
|
|
75
|
-
client.get_user_profile_url('alice', access_token)
|
|
76
|
-
client.get_my_profile_url(access_token)
|
|
90
|
+
client.get_signup_url(true, '') # the sign-up page of the application
|
|
91
|
+
client.get_user_profile_url('alice', access_token) # the profile page of a user
|
|
92
|
+
client.get_my_profile_url(access_token) # the profile page of the signed-in user
|
|
77
93
|
client.refresh_oauth_token(token['refresh_token'])
|
|
78
|
-
client.get_oauth_token_by_password('alice', 'password')
|
|
79
|
-
client.
|
|
80
|
-
client.introspect_token(token['access_token'])
|
|
81
|
-
client.logout(token['access_token'])
|
|
94
|
+
client.get_oauth_token_by_password('alice', 'password') # needs the "password" grant type in the application
|
|
95
|
+
client.impersonate_user('alice', 'master-password') # an admin acts as a user, with the organization's master password
|
|
96
|
+
client.introspect_token(token['access_token']) # => {"active" => true, ...}
|
|
97
|
+
client.logout(token['access_token']) # signs the user out of all their sessions
|
|
98
|
+
client.logout_current_session(token['access_token']) # signs the user out of the current session only
|
|
82
99
|
```
|
|
83
100
|
|
|
84
101
|
## Calling the API as a user
|
|
85
102
|
|
|
86
|
-
By default the client calls the API as the application, with the client ID and secret
|
|
87
|
-
|
|
103
|
+
By default the client calls the API as the application, with the client ID and secret. To call it as the signed-in
|
|
104
|
+
user instead, which is subject to the user's own permissions:
|
|
88
105
|
|
|
89
106
|
```ruby
|
|
90
107
|
user_client = client.with_access_token(token['access_token'])
|
|
@@ -93,28 +110,29 @@ user.display_name = 'Alice'
|
|
|
93
110
|
user_client.update_user(user)
|
|
94
111
|
```
|
|
95
112
|
|
|
96
|
-
##
|
|
113
|
+
## Users
|
|
97
114
|
|
|
98
115
|
```ruby
|
|
99
116
|
user = client.get_user('alice') # in the client's organization, or client.get_user('org/alice')
|
|
100
117
|
user.display_name = 'Alice Smith'
|
|
101
|
-
user.email = 'alice@example.com'
|
|
102
118
|
user.properties = (user.properties || {}).merge('department' => 'R&D')
|
|
103
119
|
client.update_user(user) # => true when something changed
|
|
104
|
-
|
|
105
|
-
client.update_user(user, columns: %i[display_name email]) # only update these fields
|
|
120
|
+
client.update_user_for_columns(user, %w[displayName email]) # only update these fields
|
|
106
121
|
|
|
107
122
|
client.add_user(Casdoor::User.new(name: 'bob', display_name: 'Bob', password: '123456'))
|
|
108
|
-
client.delete_user('bob')
|
|
123
|
+
client.delete_user(client.get_user('bob'))
|
|
109
124
|
|
|
110
125
|
client.get_users # => [Casdoor::User]
|
|
111
|
-
users, total = client.get_pagination_users(1, 20,
|
|
126
|
+
users, total = client.get_pagination_users(1, 20, field: 'name', value: 'a', sort_field: 'created_time')
|
|
127
|
+
client.get_sorted_users('created_time', 10)
|
|
128
|
+
client.get_global_users # the users of all the organizations
|
|
112
129
|
client.get_user_by_email('alice@example.com')
|
|
113
130
|
client.get_user_by_phone('13800000000')
|
|
114
131
|
client.get_user_by_user_id('uuid') # by the "id" field of the user
|
|
115
|
-
client.
|
|
116
|
-
client.
|
|
117
|
-
client.
|
|
132
|
+
client.update_user_by_id('casbin/alice', user) # e.g. to rename the user
|
|
133
|
+
client.get_user_count('') # "" for all, "1" for the online users, "0" for the offline ones
|
|
134
|
+
client.set_password('casbin', 'alice', 'old-password', 'new-password') # an admin can leave the old password empty
|
|
135
|
+
client.check_user_password(Casdoor::User.new(name: 'alice', password: 'password')) # => true or false
|
|
118
136
|
```
|
|
119
137
|
|
|
120
138
|
The objects (`Casdoor::User`, `Casdoor::Application`, ...) keep all the fields returned by Casdoor, so an object that is
|
|
@@ -122,35 +140,96 @@ read, changed and updated never loses the fields this SDK doesn't know about. Th
|
|
|
122
140
|
snake_case (`user.display_name`, `user.is_admin?`), or with their names in Casdoor (`user['displayName']`). The fields
|
|
123
141
|
whose names are taken by Ruby (e.g. `hash` of a user) can only be accessed with `[]`.
|
|
124
142
|
|
|
125
|
-
##
|
|
143
|
+
## The other objects
|
|
126
144
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
These methods exist for all the objects: adapters, applications, certs, enforcers, groups, invitations, models,
|
|
146
|
+
orders, organizations, payments, permissions, plans, pricings, products, providers, records, roles, sessions,
|
|
147
|
+
subscriptions, syncers, tokens, transactions, users and webhooks (the same as the Go SDK, e.g. records can't be
|
|
148
|
+
updated or deleted):
|
|
130
149
|
|
|
131
150
|
```ruby
|
|
132
151
|
client.get_roles # => [Casdoor::Role]
|
|
133
152
|
client.get_pagination_roles(1, 20) # => [[Casdoor::Role], total]
|
|
134
153
|
client.get_role('admin') # => Casdoor::Role or nil
|
|
135
154
|
client.add_role(Casdoor::Role.new(name: 'admin', users: ['casbin/alice']))
|
|
136
|
-
client.update_role(role
|
|
137
|
-
client.
|
|
155
|
+
client.update_role(role)
|
|
156
|
+
client.update_role_for_columns(role, %w[users])
|
|
157
|
+
client.delete_role(role)
|
|
138
158
|
```
|
|
139
159
|
|
|
140
|
-
Organizations, applications and
|
|
141
|
-
A different owner can be given by `"owner/name"
|
|
142
|
-
|
|
143
|
-
|
|
160
|
+
Organizations, applications, tokens and LDAP servers belong to `admin`, the other objects belong to the client's
|
|
161
|
+
organization. A different owner can be given by `"owner/name"` or by the `owner` field of the object.
|
|
162
|
+
|
|
163
|
+
More APIs of the objects:
|
|
164
|
+
|
|
165
|
+
```ruby
|
|
166
|
+
client.get_organization_applications # the applications of the client's organization
|
|
167
|
+
client.get_organization_names
|
|
168
|
+
client.get_global_certs
|
|
169
|
+
client.get_permissions_by_role('admin')
|
|
170
|
+
client.get_invitation_info('CODE', 'app-example')
|
|
171
|
+
client.get_session('alice', 'app-example')
|
|
172
|
+
client.get_user_orders('alice')
|
|
173
|
+
client.cancel_order('order-1')
|
|
174
|
+
client.get_user_payments('alice')
|
|
175
|
+
client.notify_payment(payment)
|
|
176
|
+
client.invoice_payment(payment)
|
|
177
|
+
client.get_user_transactions('alice')
|
|
178
|
+
affected, transaction_id = client.add_transaction(transaction)
|
|
179
|
+
client.add_transaction_with_dry_run(transaction, true)
|
|
180
|
+
```
|
|
144
181
|
|
|
145
|
-
##
|
|
182
|
+
## Permissions and policies
|
|
146
183
|
|
|
147
184
|
```ruby
|
|
148
|
-
|
|
149
|
-
client.
|
|
150
|
-
|
|
185
|
+
# One of the permission ID, model ID, resource ID, enforcer ID or owner chooses the policies to check
|
|
186
|
+
client.enforce('casbin/permission-1', '', '', '', '', %w[alice data1 read]) # => true or false
|
|
187
|
+
client.batch_enforce('', '', '', 'casbin/enforcer-1', '', [%w[alice data1 read], %w[bob data2 write]])
|
|
188
|
+
# => [[true, false]], the results of each permission
|
|
189
|
+
|
|
190
|
+
rule = Casdoor::CasbinRule.new(ptype: 'p', v0: 'alice', v1: 'data1', v2: 'read')
|
|
191
|
+
client.add_policy(enforcer, rule)
|
|
192
|
+
client.update_policy(enforcer, rule, new_rule)
|
|
193
|
+
client.remove_policy(enforcer, rule)
|
|
194
|
+
client.get_policies('enforcer-1', '')
|
|
195
|
+
client.get_filtered_policies('casbin/enforcer-1', [Casdoor::PolicyFilter.new(ptype: 'p', field_index: 0, field_values: ['alice'])])
|
|
151
196
|
```
|
|
152
197
|
|
|
153
|
-
|
|
198
|
+
## Orders and payments
|
|
199
|
+
|
|
200
|
+
```ruby
|
|
201
|
+
order = client.place_order([Casdoor::ProductInfo.new(name: 'product-1', quantity: 1)], 'alice')
|
|
202
|
+
payment = client.pay_order(order.name, 'provider_payment_dummy')
|
|
203
|
+
order = client.buy_product('product-1', 'provider_payment_dummy', 'alice')
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Resources, emails, SMS and notifications
|
|
207
|
+
|
|
208
|
+
```ruby
|
|
209
|
+
file_url, name = client.upload_resource('alice', 'avatar', '', 'alice.png', File.binread('alice.png'))
|
|
210
|
+
client.get_resources('casbin', 'alice', '', '', '', '')
|
|
211
|
+
client.delete_resource(client.get_resource("casbin/#{name}"))
|
|
212
|
+
|
|
213
|
+
client.send_email('Title', 'Content', 'sender', 'alice@example.com', 'bob@example.com')
|
|
214
|
+
client.send_email_by_provider('Title', 'Content', 'sender', 'provider_email', 'alice@example.com')
|
|
215
|
+
client.send_sms('Your code is 123456', '+15555550100')
|
|
216
|
+
client.send_sms_by_provider('Your code is 123456', 'provider_sms', '+15555550100')
|
|
217
|
+
client.send_notification('Content', 'recipient')
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## MFA and LDAP
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
response = client.initiate('casbin', 'app', 'alice') # => {"status" => "ok", "data" => {"secret" => ..., "url" => ...}}
|
|
224
|
+
client.verify('casbin', 'app', 'alice', secret, passcode)
|
|
225
|
+
client.enable('casbin', 'app', 'alice', secret, recovery_code)
|
|
226
|
+
client.set_preferred('casbin', 'app', 'alice', secret)
|
|
227
|
+
client.delete('casbin', 'alice') # disables the MFA of the user
|
|
228
|
+
|
|
229
|
+
client.get_ldaps
|
|
230
|
+
client.get_ldap_users('ldap-id') # => {"users" => [Casdoor::LdapUser], ...}
|
|
231
|
+
client.sync_ldap_users_from_server('ldap-id') # imports the LDAP users into Casdoor
|
|
232
|
+
```
|
|
154
233
|
|
|
155
234
|
## Errors
|
|
156
235
|
|
|
@@ -161,14 +240,14 @@ One of `permission_id:`, `model_id:`, `resource_id:`, `enforcer_id:` or `owner:`
|
|
|
161
240
|
|
|
162
241
|
## Other APIs
|
|
163
242
|
|
|
164
|
-
|
|
165
|
-
can be called with the authentication of the client:
|
|
243
|
+
Like `DoGetBytes` and `DoPost` of the Go SDK, any other API of Casdoor (see
|
|
244
|
+
[the Swagger docs](https://door.casdoor.com/swagger)) can be called with the authentication of the client:
|
|
166
245
|
|
|
167
246
|
```ruby
|
|
168
|
-
client.
|
|
169
|
-
client.
|
|
170
|
-
client.
|
|
171
|
-
client.
|
|
247
|
+
client.do_get_bytes(client.get_url('get-organization-applications', 'owner' => 'admin', 'organization' => 'casbin'))
|
|
248
|
+
client.do_get_response(client.get_url('get-sessions', 'owner' => 'casbin')) # the whole response, e.g. "data2"
|
|
249
|
+
client.do_post('add-ldap', nil, ldap) # POST with a JSON body
|
|
250
|
+
client.do_post('set-password', nil, form, true) # POST with a form body
|
|
172
251
|
```
|
|
173
252
|
|
|
174
253
|
## Development
|
|
@@ -179,8 +258,8 @@ bundle exec rubocop
|
|
|
179
258
|
bundle exec rspec
|
|
180
259
|
```
|
|
181
260
|
|
|
182
|
-
|
|
183
|
-
Casdoor with
|
|
261
|
+
Like the Go SDK, the tests of the APIs (`spec/<object>_spec.rb`, one for each `<object>_test.go`) run against a local
|
|
262
|
+
Casdoor started with `.ci/casdoor/init_data.json`; they are skipped unless `CASDOOR_TEST_ENDPOINT` is set:
|
|
184
263
|
|
|
185
264
|
```shell
|
|
186
265
|
docker run -d -p 8000:8000 -e driverName=sqlite -e dataSourceName='file:casdoor.db?cache=shared' \
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 The Casdoor Authors. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Casdoor
|
|
18
|
+
class Adapter < Entity; end
|
|
19
|
+
|
|
20
|
+
# The adapter APIs, the counterpart of adapter.go of the Go SDK
|
|
21
|
+
class Client
|
|
22
|
+
def get_adapters
|
|
23
|
+
get_objects('get-adapters', Adapter, 'owner' => organization_name)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns the objects of the page and the total count. query_map can filter and sort them, e.g.
|
|
27
|
+
# { field: "name", value: "alice", sort_field: "created_time", sort_order: "descend" }
|
|
28
|
+
def get_pagination_adapters(page, page_size, query_map = {})
|
|
29
|
+
get_pagination_objects('get-adapters', Adapter, organization_name, page, page_size, query_map)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def get_adapter(name)
|
|
33
|
+
get_object('get-adapter', Adapter, 'id' => get_id(name))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def update_adapter(adapter)
|
|
37
|
+
modify_object('update-adapter', Adapter, adapter, organization_name)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_adapter(adapter)
|
|
41
|
+
modify_object('add-adapter', Adapter, adapter, organization_name)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def delete_adapter(adapter)
|
|
45
|
+
modify_object('delete-adapter', Adapter, adapter, organization_name)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 The Casdoor Authors. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Casdoor
|
|
18
|
+
class Application < Entity; end
|
|
19
|
+
|
|
20
|
+
# The application APIs, the counterpart of application.go of the Go SDK
|
|
21
|
+
class Client
|
|
22
|
+
def get_applications
|
|
23
|
+
get_objects('get-applications', Application, 'owner' => 'admin')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The applications of the client's organization
|
|
27
|
+
def get_organization_applications
|
|
28
|
+
get_objects('get-organization-applications', Application,
|
|
29
|
+
'owner' => 'admin', 'organization' => organization_name)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def get_application(name)
|
|
33
|
+
get_object('get-application', Application, 'id' => get_admin_id(name))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def add_application(application)
|
|
37
|
+
modify_object('add-application', Application, application, 'admin')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def delete_application(application)
|
|
41
|
+
modify_object('delete-application', Application, application, 'admin')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def update_application(application)
|
|
45
|
+
modify_object('update-application', Application, application, 'admin')
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/casdoor/auth.rb
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 The Casdoor Authors. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Casdoor
|
|
18
|
+
# The core configuration. The first step to use this SDK is to create a Client with it, or to initialize the global
|
|
19
|
+
# client with Casdoor.init_config.
|
|
20
|
+
AuthConfig = Struct.new(:endpoint, :client_id, :client_secret, :certificate, :organization_name,
|
|
21
|
+
:application_name, keyword_init: true)
|
|
22
|
+
|
|
23
|
+
# The client of the Casdoor API. By default it calls the API as the application, authenticated by the client ID
|
|
24
|
+
# and the client secret. Use with_access_token to call the API as a user instead.
|
|
25
|
+
#
|
|
26
|
+
# client = Casdoor::Client.new(
|
|
27
|
+
# endpoint: "https://door.casdoor.com",
|
|
28
|
+
# client_id: "...",
|
|
29
|
+
# client_secret: "...",
|
|
30
|
+
# certificate: File.read("token_jwt_key.pem"),
|
|
31
|
+
# organization_name: "casbin",
|
|
32
|
+
# application_name: "app-example"
|
|
33
|
+
# )
|
|
34
|
+
class Client
|
|
35
|
+
attr_reader :endpoint, :client_id, :client_secret, :certificate, :organization_name, :application_name,
|
|
36
|
+
:access_token
|
|
37
|
+
# Headers added to all the requests, e.g. to pass a gateway
|
|
38
|
+
attr_accessor :custom_headers, :open_timeout, :read_timeout
|
|
39
|
+
|
|
40
|
+
# certificate is the public certificate (or public key) of the application's cert in Casdoor, in PEM format.
|
|
41
|
+
# It's only needed by parse_jwt_token.
|
|
42
|
+
def initialize(endpoint:, client_id:, client_secret:, organization_name:, application_name:, certificate: nil,
|
|
43
|
+
custom_headers: {}, access_token: nil, open_timeout: 10, read_timeout: 30)
|
|
44
|
+
@endpoint = endpoint.to_s.chomp('/')
|
|
45
|
+
@client_id = client_id
|
|
46
|
+
@client_secret = client_secret
|
|
47
|
+
@certificate = certificate
|
|
48
|
+
@organization_name = organization_name
|
|
49
|
+
@application_name = application_name
|
|
50
|
+
@custom_headers = custom_headers.dup
|
|
51
|
+
@access_token = access_token
|
|
52
|
+
@open_timeout = open_timeout
|
|
53
|
+
@read_timeout = read_timeout
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def auth_config
|
|
57
|
+
AuthConfig.new(endpoint: endpoint, client_id: client_id, client_secret: client_secret, certificate: certificate,
|
|
58
|
+
organization_name: organization_name, application_name: application_name)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns a copy of the client that calls the API as the user who owns the access token, instead of as the
|
|
62
|
+
# application. The access token is the user's OAuth access token returned by get_oauth_token,
|
|
63
|
+
# refresh_oauth_token, get_oauth_token_by_password or impersonate_user. The original client keeps using the
|
|
64
|
+
# client ID and secret, so it's safe to create one client per user request:
|
|
65
|
+
#
|
|
66
|
+
# token = client.get_oauth_token(code, state)
|
|
67
|
+
# user = client.with_access_token(token["access_token"]).get_account
|
|
68
|
+
#
|
|
69
|
+
# The APIs are still subject to the permission check of Casdoor, so a normal user can only access their own data.
|
|
70
|
+
def with_access_token(access_token)
|
|
71
|
+
Client.new(endpoint: endpoint, client_id: client_id, client_secret: client_secret,
|
|
72
|
+
organization_name: organization_name, application_name: application_name, certificate: certificate,
|
|
73
|
+
custom_headers: custom_headers, access_token: access_token, open_timeout: open_timeout,
|
|
74
|
+
read_timeout: read_timeout)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Exchanges the code that Casdoor passed to the redirect URI for the OAuth tokens. Returns the hash of the token
|
|
78
|
+
# API, like {"access_token" => "...", "id_token" => "...", "refresh_token" => "...", "token_type" => "Bearer",
|
|
79
|
+
# "expires_in" => 604800, "scope" => "read"}.
|
|
80
|
+
def get_oauth_token(code, _state = nil)
|
|
81
|
+
request_oauth_token('authorization_code', 'code' => code)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def refresh_oauth_token(refresh_token)
|
|
85
|
+
request_oauth_token('refresh_token', 'refresh_token' => refresh_token)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Gets the OAuth token via the "password" grant type, i.e. the "Resource Owner Password Credentials Grant" of
|
|
89
|
+
# OAuth 2.0. The "password" grant type must be enabled in the application's "Grant types" in Casdoor.
|
|
90
|
+
# The username is the user's name inside the application's organization, like "alice" instead of "my-org/alice".
|
|
91
|
+
def get_oauth_token_by_password(username, password)
|
|
92
|
+
request_oauth_token('password', 'username' => username, 'password' => password)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Gets an OAuth token which acts as the given user, so that an admin can call the APIs on behalf of the user,
|
|
96
|
+
# without knowing the user's own password. It's the SDK equivalent of the "Impersonation" button in Casdoor.
|
|
97
|
+
# The master_password is the "Master password" of the user's organization, it needs to be set in Casdoor first:
|
|
98
|
+
# "Organizations" -> Edit the organization -> "Master password". See: https://casdoor.ai/docs/user/impersonation
|
|
99
|
+
def impersonate_user(username, master_password)
|
|
100
|
+
get_oauth_token_by_password(username, master_password)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
def request_oauth_token(grant_type, params)
|
|
106
|
+
form = { 'grant_type' => grant_type, 'client_id' => client_id, 'client_secret' => client_secret }.merge(params)
|
|
107
|
+
request = Net::HTTP::Post.new(URI(get_url('login/oauth/access_token')))
|
|
108
|
+
request.set_form_data(form)
|
|
109
|
+
token = check_oauth_response(send_request(request, auth: false))
|
|
110
|
+
|
|
111
|
+
# Older Casdoor versions put the error into the access token, like "error: invalid client_id"
|
|
112
|
+
if token['access_token'].to_s.start_with?('error:')
|
|
113
|
+
raise ApiError, token['access_token'].delete_prefix('error:').strip
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
token
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def check_oauth_response(body)
|
|
120
|
+
if body['error']
|
|
121
|
+
message = [body['error'], body['error_description']].compact.reject(&:empty?).join(': ')
|
|
122
|
+
raise ApiError, message
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
check_response(body)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# The global client used by the module functions like Casdoor.get_users, see global.rb
|
|
130
|
+
def self.init_config(endpoint, client_id, client_secret, certificate, organization_name, application_name)
|
|
131
|
+
@global_client = new_client(endpoint, client_id, client_secret, certificate, organization_name, application_name)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def self.new_client(endpoint, client_id, client_secret, certificate, organization_name, application_name)
|
|
135
|
+
new_client_with_conf(AuthConfig.new(endpoint: endpoint, client_id: client_id, client_secret: client_secret,
|
|
136
|
+
certificate: certificate, organization_name: organization_name,
|
|
137
|
+
application_name: application_name))
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def self.new_client_with_conf(config)
|
|
141
|
+
Client.new(**config.to_h)
|
|
142
|
+
end
|
|
143
|
+
end
|
data/lib/casdoor/cert.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 The Casdoor Authors. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Casdoor
|
|
18
|
+
class Cert < Entity; end
|
|
19
|
+
|
|
20
|
+
# The cert APIs, the counterpart of cert.go of the Go SDK
|
|
21
|
+
class Client
|
|
22
|
+
# The certs of all the organizations, only allowed for global admins
|
|
23
|
+
def get_global_certs
|
|
24
|
+
get_objects('get-global-certs', Cert, nil)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_certs
|
|
28
|
+
get_objects('get-certs', Cert, 'owner' => organization_name)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def get_cert(name)
|
|
32
|
+
get_object('get-cert', Cert, 'id' => get_id(name))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def add_cert(cert)
|
|
36
|
+
modify_object('add-cert', Cert, cert, organization_name)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def update_cert(cert)
|
|
40
|
+
modify_object('update-cert', Cert, cert, organization_name)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def delete_cert(cert)
|
|
44
|
+
modify_object('delete-cert', Cert, cert, organization_name)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 The Casdoor Authors. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module Casdoor
|
|
18
|
+
# Sending emails with the email provider of the application, the counterpart of email.go of the Go SDK
|
|
19
|
+
class Client
|
|
20
|
+
def send_email(title, content, sender, *receivers)
|
|
21
|
+
form = { 'title' => title, 'content' => content, 'sender' => sender, 'receivers' => receivers.flatten }
|
|
22
|
+
do_post('send-email', nil, form)
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Sends with the given email provider instead of the application's one
|
|
27
|
+
def send_email_by_provider(title, content, sender, provider, *receivers)
|
|
28
|
+
form = { 'title' => title, 'content' => content, 'sender' => sender, 'receivers' => receivers.flatten }
|
|
29
|
+
do_post('send-email', { 'provider' => provider }, form)
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|