Skip to content

Instantly share code, notes, and snippets.

@artello73
Forked from DragonBe/azure-ad-connect.php
Created July 6, 2022 09:01
Show Gist options
  • Save artello73/86336277c1c28afaf0603d8b2dc8f873 to your computer and use it in GitHub Desktop.
Save artello73/86336277c1c28afaf0603d8b2dc8f873 to your computer and use it in GitHub Desktop.

Revisions

  1. @DragonBe DragonBe revised this gist Sep 22, 2021. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion azure-ad-connect.php
    Original file line number Diff line number Diff line change
    @@ -19,6 +19,10 @@

    require_once __DIR__ . '/vendor/autoload.php';

    //
    // THIS IS A PROOF OF CONCEPT! DO NOT USE IN PRODUCTION!!!
    //

    $https = false;
    if (isset($_SERVER['HTTPS'])) {
    $https = true;
    @@ -29,7 +33,7 @@
    // Get the root op the application
    $host = sprintf('%s://%s', ($https ? 'https' : 'http'), $_SERVER['HTTP_HOST']);

    // Routing through employee-api.php
    // Simple PHP routing
    $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    $requestPath = rtrim($path, '/');

  2. @DragonBe DragonBe created this gist Sep 22, 2021.
    201 changes: 201 additions & 0 deletions azure-ad-connect.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,201 @@
    <?php
    declare(strict_types=1);

    use League\OAuth2\Client\Provider\GenericProvider;
    use Microsoft\Graph\Graph;
    use Microsoft\Graph\Model;

    const APP_SESS_ID = 'AZPHPSID';

    const OAUTH_APP_ID = '';
    const OAUTH_APP_SECRET = '';
    const OAUTH_REDIRECT_URI = '/callback';
    const OAUTH_SCOPES = 'openid profile offline_access user.read';
    const OAUTH_AUTHORITY = 'https://login.microsoftonline.com/common';
    const OAUTH_AUTHORIZE_ENDPOINT = '/oauth2/v2.0/authorize';
    const OAUTH_TOKEN_ENDPOINT = '/oauth2/v2.0/token';

    $title = 'Hello public world!';

    require_once __DIR__ . '/vendor/autoload.php';

    $https = false;
    if (isset($_SERVER['HTTPS'])) {
    $https = true;
    } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO']) {
    $https = true;
    }

    // Get the root op the application
    $host = sprintf('%s://%s', ($https ? 'https' : 'http'), $_SERVER['HTTP_HOST']);

    // Routing through employee-api.php
    $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    $requestPath = rtrim($path, '/');

    $user = null;

    // If we run buit-in PHP web server, we want static files to be served directly
    if ('cli-server' === php_sapi_name()) {
    $staticExtensions = ['jpg', 'jpeg', 'gif', 'png', 'ico', 'js', 'css'];
    $currentExtension = pathinfo($path, PATHINFO_EXTENSION);
    if (in_array($currentExtension, $staticExtensions)) {
    return false;
    }
    }

    session_name(APP_SESS_ID);
    session_start();

    // Checking for user
    $user = [];
    if (isset($_SESSION['user'])) {
    $user = unserialize($_SESSION['user']);
    $title = 'Hello private world';
    }

    // Checking for messages
    $style = 'success';
    $displayMessage = '';
    if (isset($_GET['type']) && isset($_GET['message'])) {
    $styles = ['success', 'error'];
    if (in_array($_GET['type'], $styles)) {
    $style = $_GET['type'];
    }
    $displayMessage = $_GET['message'];
    }

    if ('/logout' === $requestPath) {
    session_destroy();
    setcookie(APP_SESS_ID, '', time() - 1000);
    header('Location: ' . $host . '/?type=success&message=Succesfully%20logged%20out');
    }

    if ('/login' === $requestPath) {
    $oAuthClient = new GenericProvider([
    'clientId' => OAUTH_APP_ID,
    'clientSecret' => OAUTH_APP_SECRET,
    'redirectUri' => $host . OAUTH_REDIRECT_URI,
    'urlAuthorize' => OAUTH_AUTHORITY . OAUTH_AUTHORIZE_ENDPOINT,
    'urlAccessToken' => OAUTH_AUTHORITY . OAUTH_TOKEN_ENDPOINT,
    'urlResourceOwnerDetails' => '',
    'scopes' => OAUTH_SCOPES,
    ]);

    $authUrl = $oAuthClient->getAuthorizationUrl();
    $_SESSION['oauthState'] = $oAuthClient->getState();
    header('Location: ' . $authUrl);
    }

    if ('/callback' === $requestPath) {
    $expectedState = $_SESSION['oauthState'];
    unset($_SESSION['oauthState']);

    if (!isset($_GET['state']) || !isset($_GET['code'])) {
    header('Location: ' . $host . '/?type=error&message=No%20OAuth%20session');
    }

    $providedState = $_GET['state'];

    if (!isset($expectedState)) {
    // If there is no expected state in the session,
    // do nothing and redirect to the home page.
    header('Location: ' . $host . '/?type=error&message=Expected%20state%20not%20available');
    }

    if (!isset($providedState) || $expectedState != $providedState) {
    header('Location: ' . $host . '/?type=error&message=State%20does%20not%20match');
    }

    // Authorization code should be in the "code" query param
    $authCode = $_GET['code'];
    if (isset($authCode)) {
    // Initialize the OAuth client
    $oAuthClient = new GenericProvider([
    'clientId' => OAUTH_APP_ID,
    'clientSecret' => OAUTH_APP_SECRET,
    'redirectUri' => $host . OAUTH_REDIRECT_URI,
    'urlAuthorize' => OAUTH_AUTHORITY . OAUTH_AUTHORIZE_ENDPOINT,
    'urlAccessToken' => OAUTH_AUTHORITY . OAUTH_TOKEN_ENDPOINT,
    'urlResourceOwnerDetails' => '',
    'scopes' => OAUTH_SCOPES,
    ]);

    $accessToken = null;
    try {
    // Make the token request
    $accessToken = $oAuthClient->getAccessToken('authorization_code', [
    'code' => $authCode
    ]);
    } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
    header('Location: ' . $host . '/?type=error&message=' . urlencode($e->getMessage()));
    }
    }

    $user = [];
    if (null !== $accessToken) {
    $graph = new Graph();
    $graph->setAccessToken($accessToken->getToken());
    try {
    $azureUser = $graph->createRequest('GET', '/me?$select=displayName,mail,userPrincipalName')
    ->setReturnType(Model\User::class)
    ->execute();
    } catch (Exception $exception) {
    header('Location: ' . $host . '/?type=error&message=' . urlencode('Unable to get user details: ' . $exception->getMessage()));
    }

    $user = [
    'name' => $azureUser->getDisplayName(),
    'email' => $azureUser->getMail(),
    ];
    $_SESSION['user'] = serialize($user);
    }
    header('Location: ' . $host);
    }
    ?>
    <!DOCTYPE html>
    <html lang="en_US">
    <head>
    <meta charset="UTF-8">
    <title><?php echo htmlentities($title, ENT_QUOTES, 'UTF-8') ?></title>
    <style type="text/css">
    html {
    font-family: Helvetica, Arial, sans-serif;
    }
    .error, .success {
    padding: 5px 15px;
    }
    .error {
    background-color: lightpink;
    border: 1px solid darkred;
    color: darkred;
    }
    .success {
    background-color: lightgreen;
    border: 1px solid darkgreen;
    color: darkgreen;
    }
    </style>
    </head>
    <body>
    <h1><?php echo htmlentities($title, ENT_QUOTES, 'UTF-8') ?></h1>
    <p>Welcome to PHP <strong><?php echo phpversion() ?></strong> on Azure App Service <strong><?php echo gethostname() ?></strong>.</p>
    <p>
    <a href="/">Home</a>
    <a href="/login">Login</a>
    <a href="/logout">Logout</a>
    </p>
    <?php if ('' !== $displayMessage): ?>
    <div class="<?php echo $style ?>">
    <p><?php echo htmlentities($displayMessage, ENT_QUOTES, 'UTF-8') ?></p>
    </div>
    <?php endif ?>
    <?php if ([] !== $user): ?>
    <p>User details</p>
    <ul>
    <li><strong>Name:</strong> <?php echo htmlentities($user['name'], ENT_QUOTES, 'UTF-8') ?></li>
    <li><strong>Email:</strong> <?php echo htmlentities($user['email'], ENT_QUOTES, 'UTF-8') ?></li>
    </ul>
    <?php endif ?>
    </body>
    </html>