Last active
December 5, 2024 12:38
-
-
Save DragonBe/8af1044185ef14e61cd98e6086e3fc59 to your computer and use it in GitHub Desktop.
A simple PoC to access Azure AD for authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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'; | |
// | |
// THIS IS A PROOF OF CONCEPT! DO NOT USE IN PRODUCTION!!! | |
// | |
$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']); | |
// Simple PHP routing | |
$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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hallo,
i'm looking for an 'authenticate with microsoft' solution for an intranet website in a school.
I've been trying to get it to work but unfortunately i'm getting an error on line 141 $graph = new Graph()
I assume it has something todo with the version composer is pulling in. This is what i have in composer.json:
"require": {
"microsoft/microsoft-graph": "^2.0"
}
could you tell me what i'm doing wrong ?