Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

Commit 926b21a

Browse files
committed
Merge branch 'use-oauth2-keycloak'
2 parents 0a5f8e3 + f619e64 commit 926b21a

35 files changed

+1375
-325
lines changed

.env.example

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
KEYCLOAK_USER_MODEL=colq2\Tests\Keycloak\Stubs\KeycloakUser
2-
KEYCLOAK_BASE_URL=https://dev.auth.fhac.hacking4.de/auth
3-
KEYCLOAK_REALM=test
4-
KEYCLOAK_CLIENT_ID=test
5-
KEYCLOAK_CLIENT_SECRET=5f98c5a4-cfe5-499c-82f0-77c1010c2767
1+
KEYCLOAK_USER_MODEL=colq2\Keycloak\KeycloakUser
2+
KEYCLOAK_BASE_URL=
3+
KEYCLOAK_REALM=
4+
KEYCLOAK_CLIENT_ID=
5+
KEYCLOAK_CLIENT_SECRET=
66
KEYCLOAK_REDIRECT=/callback
7-
KEYCLOAK_USE_NONCE=false
8-
KEYCLOAK_NONCE_LIFETIME=600
9-
10-
TEST_INTEGRATION=true
7+
KEYCLOAK_PUBLIC_KEY=

README.md

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ Feel free to contribute to this.
88
# To do
99
[ ] Allow different user storage's like Cache, Session, Eloquent, Database etc.
1010

11-
[ ] Implement nonce
12-
1311
[ ] Write Readme
1412

15-
[ ] Middleware for roles and scopes
16-
13+
[ ] Upload to packagist
1714

1815
# Installation
1916
`composer require colq2/laravel-keycloak`
@@ -29,7 +26,8 @@ This project redefines the user model and migrations. There is no need for passw
2926
* name
3027
* email
3128
* picture
32-
29+
* roles
30+
3331
You can delete all migrations in your laravel project if you want to use keycloak as the only auth possibility.
3432

3533

@@ -42,9 +40,6 @@ KEYCLOAK_REALM=
4240
KEYCLOAK_CLIENT_ID=
4341
KEYCLOAK_CLIENT_SECRET=
4442
KEYCLOAK_REDIRECT=/callback
45-
KEYCLOAK_USE_NONCE=false
46-
KEYCLOAK_NONCE_LIFETIME=600
47-
KEYCLOAK_MAX_AGE=86400
4843
```
4944

5045
## Usage
@@ -89,6 +84,33 @@ Route::get('callback', 'LoginController@handleCallback');
8984
```
9085

9186

87+
## Middleware
88+
This package comes with `CheckRealmAccess` and `CheckResourceAccess` middleware. You can add them in the `app/Http/Kernel.php` file.
89+
90+
```
91+
protected $routeMiddleware = [
92+
// ...
93+
'realm_access' => \colq2\Keycloak\Http\Middleware\CheckRealmAccess::class,
94+
'resource_access' => \colq2\Keycloak\Http\Middleware\CheckResourceAccess::class,
95+
];
96+
```
97+
98+
Then you can use the middleware:
99+
100+
### Realm Access Middleware
101+
102+
```
103+
Route::get('post/{post}', function(Post $post) {
104+
// The current user has role1 and role2 in the realm
105+
})->middleware('realm_access:role1,role2');
106+
```
107+
108+
### Resource Access Middleware
109+
```
110+
Route::get('post/{post}', function(Post $post) {
111+
// The current user has role1 and role2 in client1 in the realm
112+
})->middleware('resource_access:client1,role1,role2');
113+
```
92114

93115
## Custom User
94116

@@ -115,6 +137,7 @@ By default you can use all claims that are defined in the openid-connect specs.
115137
$table->string('email')->nullable();
116138
$table->string('name')->nullable();
117139
$table->string('picture')->nullable();
140+
$table->json('roles')->nullable();
118141
$table->rememberToken();
119142
$table->timestamps();
120143
});
@@ -128,40 +151,31 @@ After you defined which properties you need. You have to define the same in the
128151
```
129152
<?php
130153
131-
namespace App;
154+
namespace colq2\Keycloak;
132155
133-
use Illuminate\Notifications\Notifiable;
134-
use colq2\Keycloak\KeycloakUser as Authenticatable;
156+
use colq2\Keycloak\Contracts\Roles\HasRoles;
157+
use Illuminate\Auth\Authenticatable;
158+
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
159+
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
160+
use Illuminate\Database\Eloquent\Model;
161+
use Illuminate\Foundation\Auth\Access\Authorizable;
135162
136-
class User extends Authenticatable
163+
class KeycloakUser extends Model implements AuthenticatableContract, AuthorizableContract, HasRoles
137164
{
138-
use Notifiable;
165+
use Authenticatable, Authorizable;
139166
140-
/**
141-
* @var string
142-
*/
143167
protected $table = 'users';
144168
145-
/**
146-
*
147-
* The attributes that are mass assignable.
148-
*
149-
* @var array
150-
*/
151-
protected $fillable = [
152-
// TODO: Update the fillable
153-
'sub, 'username', 'name', 'email', 'picture'
154-
];
169+
protected $fillable = [ 'sub', 'username', 'name', 'email', 'picture', 'roles' ];
155170
156-
/**
157-
* The attributes that should be hidden for arrays.
158-
*
159-
* @var array
160-
*/
161-
protected $hidden = [
162-
'remember_token',
163-
];
171+
protected $casts = [ 'roles' => 'array' ];
164172
173+
protected $hidden = [ 'remember_token' ];
174+
175+
public function getAllRoles(): array
176+
{
177+
return $this->roles;
178+
}
165179
}
166180
167181
```
@@ -174,22 +188,26 @@ Then update the app binding to your user service.
174188
In CustomUserService:
175189

176190
```
191+
<?php
192+
193+
namespace colq2\Keycloak\Examples;
194+
177195
use colq2\Keycloak\KeycloakUserService;
178-
use colq2\Keycloak\SocialiteOIDCUser;
179196
180197
class CustomUserService extends KeycloakUserService
181198
{
182199
183-
public function mapSocialiteUserToKeycloakUser(SocialiteOIDCUser $user)
200+
/**
201+
* @param array $user
202+
* @return array|\colq2\Keycloak\KeycloakUser
203+
*/
204+
public function mapUser(array $user): array
184205
{
185-
$keycloakUser = (array) $user;
186-
187-
// DO whatever you need
188-
189-
// For example
190-
$keycloakUser['username'] = $keycloakUser['preferred_username'];
206+
// Do whatever you need
207+
$user['username'] = $user['preferred_username'];
191208
192-
return $keycloakUser;
209+
// And return it
210+
return $user;
193211
}
194212
}
195213
```

composer.json

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,22 @@
1010
"email": "development@o-wycisk.de"
1111
}
1212
],
13+
"repositories": [
14+
{
15+
"type": "vcs",
16+
"url": "https://github.com/colq2/oauth2-keycloak"
17+
}
18+
],
1319
"require": {
1420
"php": "^7.1",
15-
"laravel/socialite": "^4.1",
16-
"lcobucci/jwt": "^3.2",
1721
"illuminate/auth": "^5.7",
1822
"illuminate/cache": "^5.7",
1923
"illuminate/contracts": "5.7.*",
2024
"illuminate/session": "^5.7",
21-
"illuminate/support": "^5.7"
25+
"illuminate/support": "^5.7",
26+
"stevenmaguire/oauth2-keycloak": "dev-master",
27+
"lcobucci/jwt": "^3.2",
28+
"ext-json": "*"
2229
},
2330
"require-dev": {
2431
"orchestra/testbench": "~3.7",
@@ -28,8 +35,7 @@
2835
"autoload": {
2936
"psr-4": {
3037
"colq2\\Keycloak\\": "src/"
31-
},
32-
"files": ["src/helpers.php"]
38+
}
3339
},
3440
"autoload-dev": {
3541
"psr-4": {

config/keycloak.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
'redirect' => env('KEYCLOAK_REDIRECT'),
88
'realm' => env('KEYCLOAK_REALM'),
99
'base_url' => env('KEYCLOAK_BASE_URL'),
10+
'public_key' => env('KEYCLOAK_PUBLIC_KEY')
1011
];

database/migrations/2019_02_28_000000_create_Keycloak_users_table.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php
22

3-
use Illuminate\Support\Facades\Schema;
4-
use Illuminate\Database\Schema\Blueprint;
53
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
66

77
class CreateKeycloakUsersTable extends Migration
88
{
@@ -20,6 +20,7 @@ public function up()
2020
$table->string('email')->nullable();
2121
$table->string('name')->nullable();
2222
$table->string('picture')->nullable();
23+
$table->json('roles')->nullable();
2324
$table->rememberToken();
2425
$table->timestamps();
2526
});

examples/CustomUserService.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@
33
namespace colq2\Keycloak\Examples;
44

55
use colq2\Keycloak\KeycloakUserService;
6-
use colq2\Keycloak\SocialiteOIDCUser;
76

87
class CustomUserService extends KeycloakUserService
98
{
109

11-
public function mapSocialiteUserToKeycloakUser(SocialiteOIDCUser $user)
10+
/**
11+
* @param array $user
12+
* @return array|\colq2\Keycloak\KeycloakUser
13+
*/
14+
public function mapUser(array $user): array
1215
{
13-
$keycloakUser = (array) $user;
16+
// Do whatever you need
17+
$user['username'] = $user['preferred_username'];
1418

15-
// DO whatever you need
16-
17-
// For example
18-
$keycloakUser['username'] = $keycloakUser['preferred_username'];
19-
20-
return $keycloakUser;
19+
// And return it
20+
return $user;
2121
}
2222
}

src/ConfigKeyFetcher.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace colq2\Keycloak;
4+
5+
6+
use colq2\Keycloak\Contracts\KeyFetcher;
7+
8+
class ConfigKeyFetcher implements KeyFetcher
9+
{
10+
11+
/**
12+
* Fetch and return key
13+
*
14+
* @return string
15+
*/
16+
public function fetchKey(): string
17+
{
18+
$publicKey = config('keycloak.public_key', "");
19+
20+
if (empty($publicKey)) {
21+
return $publicKey;
22+
}
23+
24+
return $this->generatePublicKey($publicKey);
25+
}
26+
27+
28+
/**
29+
* Add begin and end to public key
30+
*
31+
* @param string $publicKey
32+
* @return string
33+
*/
34+
protected function generatePublicKey(string $publicKey)
35+
{
36+
if (strpos($publicKey, "-----BEGIN") === false) {
37+
return "-----BEGIN PUBLIC KEY-----" . PHP_EOL . $publicKey . PHP_EOL . '-----END PUBLIC KEY-----' . PHP_EOL;
38+
}
39+
return $publicKey;
40+
}
41+
42+
}

src/Contracts/KeyFetcher.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace colq2\Keycloak\Contracts;
4+
5+
6+
interface KeyFetcher
7+
{
8+
9+
/**
10+
* Fetch and return key
11+
*
12+
* @return string
13+
*/
14+
public function fetchKey(): string;
15+
16+
}

src/Contracts/Roles/HasRoles.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace colq2\Keycloak\Contracts\Roles;
4+
5+
6+
interface HasRoles
7+
{
8+
/**
9+
* Returns all roles in an assoc array in form of
10+
* [
11+
* realm_access => [roles => [ ... ] ]
12+
*
13+
* resource_access => [
14+
* client => [ roles [ ... ] ]
15+
* ]
16+
* ]
17+
*
18+
* @return array
19+
*/
20+
public function getAllRoles(): array;
21+
}

0 commit comments

Comments
 (0)