Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,13 @@ MAILER_DEFAULT_TO_EMAIL="mailer_default_to_email_is_misconfigured@tesuta.be"
SITE_TITLE="Your application"
ENCRYPTION_KEY="8ea13de9680e2a1441774ec26642fa65a56d8099f44a301f219864b51bbaa925"
###< sumocoders/framework-core-bundle ###

###> hwi/oauth-bundle ###
AZURE_CLIENT_ID=
AZURE_CLIENT_SECRET=
AZURE_TENANT_ID=

SUMOCODERS_CLIENT_ID=
SUMOCODERS_CLIENT_SECRET=
SUMOCODERS_TENANT_ID=
###< hwi/oauth-bundle ###
58 changes: 53 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ All commands and paths in these steps assume the current working directory is th
</constraints>

<steps>
1. From the project root, clone the reference repository: `git clone https://github.com/sumocoders/Framework-User-Implementation-Example.git ./temp`
1. From the project root, clone the reference repository: `git clone https://github.com/sumocoders/Framework-User-Implementation-Example.git ./temp`.
And checkout the `HWIOAuthBundle-implementation` branch: `git -C ./temp checkout HWIOAuthBundle-implementation`.

2. Install packages: `symfony composer require 2fa scheb/2fa-backup-code scheb/2fa-totp scheb/2fa-trusted-device endroid/qr-code`
- If `Scheb\TwoFactorBundle\SchebTwoFactorBundle::class` is missing from `config/bundles.php`, add it: `Scheb\TwoFactorBundle\SchebTwoFactorBundle::class => ['all' => true]`
Expand Down Expand Up @@ -61,11 +62,58 @@ All commands and paths in these steps assume the current working directory is th

6. Copy `src/EventListener` from `./temp` into the project's `src/` directory.

7. Copy all files from `./temp/src/Migrations/` into `src/Migrations/`, then run: `symfony console doctrine:migrations:migrate`
7. Copy all files from `./temp/migrations/` into `migrations/`, then run: `symfony console doctrine:migrations:migrate`

8. From the project root, remove the temp folder: `rm -rf ./temp`

9. Ask the user which optional features to remove, then apply:
- No profile page: remove `src/Controller/User/ProfileController.php`, `templates/user/profile.html.twig`, and the profile navigation entry in `templates/user/_profile_navigation.html.twig`
- No registration: remove `src/Controller/User/RegisterController.php`, `src/Message/User/RegisterUser.php`, `src/MessageHandler/User/RegisterUserHandler.php`, `templates/user/register.html.twig`
9. If the user wants Azure Entra ID (SSO) login support, perform all of the following sub-steps; otherwise skip to step 10:
a. Install the bundle: `symfony composer require hwi/oauth-bundle`
- If `HWI\Bundle\OAuthBundle\HWIOAuthBundle::class` is missing from `config/bundles.php`, add it: `HWI\Bundle\OAuthBundle\HWIOAuthBundle::class => ['all' => true]`
b. Copy from `./temp` into the project, preserving paths:
- `config/packages/hwi_oauth.yaml`
- `config/routes/hwi_oauth_routing.yaml`
- `src/Security/OAuth/AzureUserProvider.php`
- `src/Event/User/AzureLoginEvent.php`
- `migrations/Version20260512135528.php`
c. In `src/Entity/User/User.php`, copy from `./temp`: the `azureObjectId` property and the methods `createFromAzureProfile()`, `linkAzureAccount()`, `unlinkAzureAccount()`, `isAzureUser()`, `getAzureObjectId()`, `syncAzureRoles()`
d. In `src/Controller/User/LoginController.php`, copy from `./temp`: the `$azureClientId` and `$sumocodersClientId` constructor arguments and the template variables that pass them to the view
e. In `templates/user/login.html.twig`, copy from `./temp`: the "Sign in with Microsoft" buttons
f. From the project root, remove the temp folder: `rm -rf ./temp`
g. In `config/packages/security.yaml`, add inside the `main` firewall:
```yaml
entry_point: App\Security\CustomAuthenticator
oauth:
resource_owners:
azure: /login/check-azure
sumocoders: /login/check-sumocoders
login_path: /login
failure_path: /login
oauth_user_provider:
service: App\Security\OAuth\AzureUserProvider
```
Add to `access_control` (before existing rules):
```yaml
- { path: '^/login/check-azure', roles: PUBLIC_ACCESS }
- { path: '^/login/check-sumocoders', roles: PUBLIC_ACCESS }
- { path: '^/connect/', roles: PUBLIC_ACCESS }
```
h. Add to `.env.local`:
```
###> hwi/oauth-bundle ###
AZURE_CLIENT_ID=
AZURE_CLIENT_SECRET=
AZURE_TENANT_ID=

SUMOCODERS_CLIENT_ID=
SUMOCODERS_CLIENT_SECRET=
SUMOCODERS_TENANT_ID=
###< hwi/oauth-bundle ###
```
i. Run: `symfony console doctrine:migrations:migrate`

10. Ask the user which optional features to remove, then apply:

**Profile page**: remove `src/Controller/User/ProfileController.php`, `templates/user/profile.html.twig`, and the profile navigation entry in `templates/user/_profile_navigation.html.twig`

**Registration**: remove `src/Controller/User/RegisterController.php`, `src/Message/User/RegisterUser.php`, `src/MessageHandler/User/RegisterUserHandler.php`, `templates/user/register.html.twig`
</steps>
166 changes: 164 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,171 @@ Copy the `EventListener` folder from `src/` into your own project. Or adjust you

### Alter the database

* Copy the migrations from `src/Migrations/` into your own project.
* Copy the migrations from `migrations/` into your own project.
* Run the migrations: `symfony console doctrine:migrations:migrate`

### Azure SSO (optional)

This project includes optional Azure Entra ID (SSO) support via `hwi/oauth-bundle`.
Users can log in with their Microsoft account alongside — or instead of — local email/password accounts.

#### Create an application in Azure

* Go to **[Azure Portal](https://portal.azure.com/)**
* Search for "App registrations"
* Click "New registration"
* Name: the name of the application, e.g. the URL of the web application
* Supported account types: select "Accounts in this organizational directory only (... only - Single tenant)"
* Redirect URI — you will need to add extra URLs later on:
* Platform: Web, URL: `https://project.client.wip/login/check-azure`
* You will be redirected to the newly created app registration
* Note down the **Application (client) ID** and **Directory (tenant) ID**
* Click "Redirect URIs" → "Add URI" and add all required URLs, then save. E.g.:
* `https://project.client.wip/login/check-azure`
* `https://project.client.phpXX.sumocoders.eu/login/check-azure`
* Click "Certificates & Secrets" → "New client secret"
* Description: the URL of the web application
* Expires: 12 months, or as long as you are comfortable with
* Click "Add"
* Note down the **Value** (the secret itself — the Secret ID is not needed)
* Provide the following to your integrator:
* Application (client) ID
* Directory (tenant) ID
* Client secret Value

Full article: **[Register a Microsoft Entra app and create a service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal)**

#### Allow the application to be used

When this is done, you still need to allow the users to use this application:

* Go to **[Azure Portal](https://portal.azure.com/)**
* Search for "App registrations"
* Select the newly created application
* Select "Manage → API Permissions" on the left
* Click "Grant admin consent for ..."

Full article: **[Grant tenant-wide admin consent to an application](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/grant-admin-consent?pivots=portal)**

#### Configure the roles

* Go to the **[Azure Portal](https://portal.azure.com/)**
* Search for "App registrations"
* Select your application
* Click "Manage → App roles" on the left
* Create a role for each role in your application:
* Display name: a readable label, e.g. "Admin"
* Allowed member types: Both
* Value: the Symfony role name, e.g. `ROLE_ADMIN`
* Enable this app role: yes

Full article: **[Add app roles to your application and receive them in the token](https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps)**

#### Give users a role

* Go to the **[Azure Portal](https://portal.azure.com/)**
* Search for "Microsoft Entra ID"
* Click "Manage → Enterprise applications" on the left
* Select your created application
* Select "Manage → Users and groups" on the left
* Add users/groups with the correct role

Full article: **[Assign users and groups to roles](https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps#assign-users-and-groups-to-roles)**

#### Install the bundle

```
symfony composer require hwi/oauth-bundle
```

This will normally register the bundle automatically. If not, add it to `config/bundles.php`:

```php
HWI\Bundle\OAuthBundle\HWIOAuthBundle::class => ['all' => true],
```

#### Copy the files from this project

* `config/packages/hwi_oauth.yaml`
* `config/routes/hwi_oauth_routing.yaml`
* `src/Security/OAuth/AzureUserProvider.php`
* `src/Event/User/AzureLoginEvent.php`
* The `azure_object_id` parts from `src/Entity/User/User.php`:
`azureObjectId` property, `createFromAzureProfile()`, `linkAzureAccount()`, `unlinkAzureAccount()`, `isAzureUser()`, `getAzureObjectId()`, `syncAzureRoles()`
* The `$azureClientId` and `$sumocodersClientId` constructor arguments and template variables from `src/Controller/User/LoginController.php`
* The "Sign in with Microsoft" buttons from `templates/user/login.html.twig`
* The `migrations/Version20260512135528.php` migration

#### Add the env variables

Add the following to your `.env.local` file:

```
###> hwi/oauth-bundle ###
AZURE_CLIENT_ID=
AZURE_CLIENT_SECRET=
AZURE_TENANT_ID=

SUMOCODERS_CLIENT_ID=
SUMOCODERS_CLIENT_SECRET=
SUMOCODERS_TENANT_ID=
###< hwi/oauth-bundle ###
```

#### Update security.yaml

Add the `oauth` block to your main firewall and the public access routes:

```yaml
firewalls:
main:
# ... existing config ...
entry_point: App\Security\CustomAuthenticator
oauth:
resource_owners:
azure: /login/check-azure
sumocoders: /login/check-sumocoders
login_path: /login
failure_path: /login
oauth_user_provider:
service: App\Security\OAuth\AzureUserProvider

access_control:
- { path: '^/login/check-azure', roles: PUBLIC_ACCESS }
- { path: '^/login/check-sumocoders', roles: PUBLIC_ACCESS }
- { path: '^/connect/', roles: PUBLIC_ACCESS }
# ... existing rules ...
```


#### Run the migration

The `azure_object_id` column is added via a dedicated migration so projects that do not need Azure SSO can skip it:

```
symfony console doctrine:migrations:migrate
```

#### SumoCoders login (optional)

To allow SumoCoders developers to log in with their `@sumocoders.be` accounts, a second Azure app registration is needed in the SumoCoders tenant. This is separate from the client's app registration.

Add the following redirect URIs to the SumoCoders app registration in the Azure Portal:

* `https://project.client.wip/login/check-sumocoders`
* `https://project.client.phpXX.sumocoders.eu/login/check-sumocoders`


Add the credentials to `.env.local`:

```
SUMOCODERS_CLIENT_ID=
SUMOCODERS_CLIENT_SECRET=
SUMOCODERS_TENANT_ID=
```

The "Sign in with Microsoft (SumoCoders)" button appears automatically on the login page when `SUMOCODERS_CLIENT_ID` is set. Leave it empty to hide the button.

### Cleanup

#### Profile page
Expand All @@ -94,4 +256,4 @@ If your project does not need registration, you can remove:

### AI agent instructions

See [AGENTS.md](AGENTS.md) for step-by-step instructions for AI agents.
See [AGENTS.md](AGENTS.md) for step-by-step instructions for AI agents.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"beberlei/doctrineextensions": "^1.5",
"doctrine/doctrine-migrations-bundle": "^4.0",
"endroid/qr-code": "^6.1",
"hwi/oauth-bundle": "^2.5",
"nelmio/security-bundle": "^3.7",
"scheb/2fa-backup-code": "^8.3",
"scheb/2fa-bundle": "^8.3",
Expand Down
Loading