One of the things that I’m doing is looking around at integrations and integration management. As a Linux-based PHP developer I have had a cloudy view of much of the Microsoft server world. I use Windows for most of my development and I use my Mac largely for creating videos… showcasing software I wrote on my Windows machine, for Linux… 🙂
But the Microsoft world has also made me a little jealous. There is something nice about simply having to go to one company and say “I need X” and, lo, you have it. Clearly that’s an over-simplification and, to some degree, a lie, but for the Microsoft developers I’ve talked to who have had to make the switch to PHP that is one of the things that they have said the liked better about Microsoft.
This is a simple library that uses the league/oauth2-client
to provide OAuth2 based integration with Active Directory. Out of the box it is configured to work with Active Directory on Azure but, though I haven’t tested it, you can provide a different configuration object to the primary adapter and you should be able to authenticate against any Active Directory implementation as long as it has OAuth2 connectivity.
There are two purposes (well, three) for library.
- Provide sub-5 minute installation and integration times for any PHP-based application
- Provide a launching pad for other third-party integrations to Microsoft Azure Active Directory, such as Magento, Drupal, Oro, or whatever.
- (provide libraries that use other Magium libraries so people can see how awesome all the Magium stuff is)
First, watch the installation video on YouTube. It shows you how to create an application in Azure Active Directory.
Note Azure will not redirect from a secure URL (i.e. their login page) to an unsecure page (i.e. your page). No HTTPS to HTTP in other words. In yet other words, if you use Azure you will need to also use HTTPS. Though there are worse things in the world… like not using HTTPS.
Basic Usage
Anywhere in your application that requires authentication you can provide this code (properly architected, not cut and paste, in other words):
$ad = new \Magium\ActiveDirectory\ActiveDirectory(
$configuration, // shown later
$psr7CompatibleRequest
);
$entity = $ad->authenticate();
The authenticate()
method will do 1 of 3 things.
- Check the session and see that the user is not logged in, forwarding that person to their Azure Active Directory login page
- Validate return data from Active Directory
- Simply return the
Entity
object if the person is already logged in.
If you want to log out all you do is:
$ad->forget();
Not that this only purges the AD entity from the session, it does not do any other session cleanup for your application.
Clearly this library is not intended to be your only means of session management, though, for simple applications, you could use it that way. Most likely you will want to take the data retrieved from AD and link it to a local account. The Entity
class has 3 defined getters to help you do this mapping:
echo $entity->getName() . '<Br />'; // The user's name
echo $entity->getOid() . '<Br />'; //The user's AD object ID, useful for mapping to a local user obhect
echo $entity->getPreferredUsername() . '<Br />'; // The user's username, usually an email address.
Installation
composer require magium/active-directory
Done.
Configuration
This is a little more in-depth, but it should be overly complex.
The base configuration is managed by the Magium Configuration Manager, out of the box. But, that said, the MCM has a really simple mechanism that allows you to not use the underlying plumbing. I believe that the underlying plumbing will eventually make application management easier, but I’m not going to force it on you.
Configuration using the Magium Configuration Manager
The configuration manager provides the means to manage and deploy settings at runtime in both a CLI and (eventually) a web-based interface. If you are using the configuration manager you need to get an instance of the configuration factory, which provides an instance of the manager, which provides the configuration object. The ActiveDirectory
adapter requires that configuration object.
// Convert to PSR7 request object
$request = \Zend\Psr7Bridge\Psr7ServerRequest::fromZend(
new \Zend\Http\PhpEnvironment\Request()
);
$factory = new \Magium\Configuration\MagiumConfigurationFactory();
$manager = $factory->getManager();
$configuration = $manager->getConfiguration();
$adapter = new \Magium\ActiveDirectory\ActiveDirectory($configuration, $request);
$entity = $adapter->authenticate();
First, in your application root directory run vendor/bin/magium magium:configuration:list-keys
. This is done after you have configured the MCM according to its instructions in the GitHub link. You will see output like this:
Valid configuration keys
magium/ad/client_id
(You need to configure an application in Active Directory and enter its ID here)
magium/ad/client_secret
(When you created an application in Active Directory you should have received a one-time use key. Enter that here.)
You will need to provide those two values for the configuration:
vendor/bin/magium magium:configuration:set magium/ad/client_id '<my client id>'
Set magium/ad/client_id to <my client id> (context: default)
Don't forget to rebuild your configuration cache with magium:configuration:build
vendor/bin/magium magium:configuration:set magium/ad/client_secret '<my client secret>'
Set magium/ad/client_secret to <my client secret> (context: default)
Don't forget to rebuild your configuration cache with magium:configuration:build
vendor/bin/magium magium:configuration:build
Building context: default
Building context: production
Building context: development
And you should be good to go.
Configuration using PHP Arrays
Now, I know the MCM is new and you probably aren’t using it. That’s why I provided a way for you configure the adapter without using the full-blown MCM. You can use the Magium\Configuration\Config\Repository\ArrayConfigurationRepository
class to provide a raw array that will be mapped to the two configuration settings magium/ad/client_id
and magium/ad/client_secret
session_start();
$config = [
'magium' => [
'ad' => [
'client_id' => '<my client id>',
'client_secret' => '<my client secret>'
]
]
];
$request = new \Zend\Http\PhpEnvironment\Request();
$ad = new \Magium\ActiveDirectory\ActiveDirectory(
new \Magium\Configuration\Config\Repository\ArrayConfigurationRepository($config),
Zend\Psr7Bridge\Psr7ServerRequest::fromZend(new \Zend\Http\PhpEnvironment\Request())
);
$entity = $ad->authenticate();
echo $entity->getName() . '<Br />';
echo $entity->getOid() . '<Br />';
echo $entity->getPreferredUsername() . '<Br />';
Configuration using YAML
Pretty much the same, but rather than using the ArrayConfigurationRepository
you will use the YamlConfigurationRepository
. It’s pretty similar:
$yaml = <<<YAML
magium:
ad:
client_id: value
client_secret: value
YAML;
$obj = new YamlConfigurationRepository(trim($yaml));
$ad = new \Magium\ActiveDirectory\ActiveDirectory(
$obj, $request
);
$entity = $ad->authenticate();
Configuration using JSON
Pretty much the same, but rather than using the YamlConfigurationRepository
you will use the JsonConfigurationRepository
. It’s pretty similar:
$json = <<<JSON
{
"magium": {
"ad": {
"client_id": "value"
"client_secret": "value"
}
}
}
JSON;
$obj = new JsonConfigurationRepository(trim($json));
$ad = new \Magium\ActiveDirectory\ActiveDirectory(
$obj, $request
);
$entity = $ad->authenticate();
Configuration using INI Files
Pretty much the same, but rather than using the JsonConfigurationRepository
you will use the IniConfigurationRepository
. It’s pretty similar:
$ini = <<<INI
[magium]
ad[client_id] = value
ad[client_srcret] = value
INI;
$obj = new IniConfigurationRepository(trim($ini));
$ad = new \Magium\ActiveDirectory\ActiveDirectory(
$obj, $request
);
$entity = $ad->authenticate();
Comments
PHP Annotated Monthly – May 2017 | PhpStorm Blog
[…] (Almost) Stupid Easy PHP Integration with Active Directory on Azure […]
Ken
Thanks for this wonderful library. I have a blocker though, when i run script i get
Fatal error: Uncaught exception ‘Magium\ActiveDirectory\InvalidRequestException’ with message ‘Do not authenticate if the Active Directory integration is not enabled’ in C:\wamp64\www\magium\vendor\magium\active-directory\src\ActiveDirectory.php on line 154
Where can i enable Active Directory Integration?
Ken
Yeah i figured it out,
$config = [
‘magium’ => [
‘ad’ => [
‘client_id’ => ”,
‘client_secret’ => ”,
‘enabled’ => true
]
]
];
and also, anyone using this library ensure to use authentication as array key instead of the magium
$config = [
‘magium’ => [
‘ad’ => [
‘client_id’ => ”,
‘client_secret’ => ”,
‘enabled’ => true
]
]
];
because the active directory class constants are defined as
const CONFIG_CLIENT_ID = ‘authentication/ad/client_id’;
const CONFIG_CLIENT_SECRET = ‘authentication/ad/client_secret’;
const CONFIG_ENABLED = ‘authentication/ad/enabled’;
const CONFIG_RETURN_URL = ‘authentication/ad/return_url’;
const CONFIG_REMAP_HTTPS = ‘authentication/ad/remap_https’;
const CONFIG_TENANT = ‘authentication/ad/directory’;
Anyways my sincere appreciation to the authors of the Magium Library, you’all are the best.
K J Ramana Rao
Did you upgraded your module on composer. It is not working on latest version of league oauth2 module
Kevin Schroeder
I’ve not made any recent changes to the module.
Kevin Schroeder
I also just ran a test locally and I was able to login.
Noob ToAzureAD
I need to use Azure AD Auth to access an API, and I’d like to use this Library. I’m still fairly new to OAuth2 with Azure. Is it possible to use an AD account through only code with no user interaction? Meaning no one has to type in their Azure AD Creds, I provide them via a configuration file or am I completely off base and am supposed to go about that a different way?
I see I can set PreferredUsername, but does that include something like a default username / pass to use automatically when authenticating?
Kevin Schroeder
From the perspective of this library, any user credentials should be unnecessary. The whole point of this kind of authentication scheme is to not require any kind of credentials for the user in your application. Unless, I’m misunderstanding your question.
Jose Urrego
The example returned this error (excuse my english)
Fatal error: Uncaught League\OAuth2\Client\Provider\Exception\IdentityProviderException: invalid_client in D:\Development\Project\Php\active-directory-develop\vendor\league\oauth2-client\src\Provider\GenericProvider.php:216 Stack trace: #0 D:\Development\Project\Php\active-directory-develop\vendor\league\oauth2-client\src\Provider\AbstractProvider.php(641): League\OAuth2\Client\Provider\GenericProvider->checkResponse() #1 D:\Development\Project\Php\active-directory-develop\vendor\league\oauth2-client\src\Provider\AbstractProvider.php(557): League\OAuth2\Client\Provider\AbstractProvider->getResponse() #2 D:\Development\Project\Php\active-directory-develop\src\Delegates\Receive.php(81): League\OAuth2\Client\Provider\AbstractProvider->getAccessToken() #3 D:\Development\Project\Php\active-directory-develop\src\ActiveDirectory.php(179): Magium\ActiveDirectory\Delegates\Receive->execute() #4 D:\Development\Project\Php\active-directory-develop\examples\server\index.php(37): Magium\ActiveDirectory\ActiveDirectory->authenticate() in D:\Development\Project\Php\active-directory-develop\vendor\league\oauth2 client\src\Provider\GenericProvider.php on line 216
i will try downgrade the league\OAuth2\Client to 1.4 version, but don’t work anyway.
Kevin Schroeder
Please check https://github.com/magium/active-directory/issues/36
Nicolas
Dear Kevin
I use your PHP integration component with azure AD, the productive server goes through a proxy, can you tell me where I should assign the proxy address.
Thanking you in advance
Nicolas