Add files via upload

This commit is contained in:
Token2
2024-11-25 15:25:00 +01:00
committed by GitHub
parent 7c506f3671
commit 51fde44c04
2 changed files with 378 additions and 2 deletions
+102 -2
View File
@@ -1,2 +1,102 @@
# token_inventory
Entra ID - Hardware token inventory portal
# Entra ID - Hardware token inventory portal
## Overview
This is a simple, lightweight web application built in PHP to manage hardware OATH tokens using the Microsoft Graph API. It includes features such as listing tokens, importing token configurations via JSON files, and providing an intuitive and responsive interface with Bootstrap.
---
## Features
- **Authentication**:
- Form-based password protection for secure access.
- **Token Management**:
- View a list of hardware OATH tokens.
- Includes key details like Serial Number, Device (Manufacturer/Model), Assigned User, Status, and Last Used.
- **Import Functionality**:
- Upload and import tokens using a JSON file.
- **Responsive Design**:
- Utilizes [Bootstrap](https://getbootstrap.com/) for a clean and responsive UI.
- **Interactive Table**:
- Integrated with [DataTables](https://datatables.net/) for sorting, searching, and pagination.
---
## Installation
1. Clone the repository:
```bash
git clone https://github.com/YOUR_USERNAME/hardware-token-management.git
cd hardware-token-management
```
2. Update the configuration in `index.php`:
- Replace the following placeholders with your own values:
$tenantId = 'YOUR_TENANT_ID';
$clientId = 'YOUR_CLIENT_ID';
$clientSecret = 'YOUR_CLIENT_SECRET';
$valid_username = 'username to access this app'; // Set your username
$valid_password = 'password to access the app'; // Set your password
3. Deploy the application on a PHP-compatible server (e.g., Apache, Nginx).
4. Access the application in your browser.
---
## Usage
1. **Login**:
- Access the portal using the predefined username and password (`admin/password123` by default).
- Update these credentials in `index.php`.
2. **Import Tokens**:
- Use the **Import Tokens** button to upload a JSON file with the token details. This format is available in Token2's seed request form.
- Example JSON format:
```json
[
{
"serialNumber": "8659623852751",
"secretKey": "ABC1234567890DEF",
"manufacturer": "Token2",
"model": "C202",
"timeIntervalInSeconds": 30,
"hashFunction": "hmacsha1"
}
]
```
3. **View Tokens**:
- Explore the table with token details.
- Use search and sorting features provided by DataTables for quick navigation.
---
## Screenshots
**Login Page**
[Insert Screenshot Here]
**Token List**
[Insert Screenshot Here]
**Import Modal**
[Insert Screenshot Here]
---
## License
This project is open-source and available under the [MIT License](LICENSE).
---
## Acknowledgments
- [Microsoft Graph API](https://learn.microsoft.com/en-us/graph/overview)
- [Token2](https://www.token2.com) for hardware tokens
- [Bootstrap](https://getbootstrap.com/) for responsive design
- [DataTables](https://datatables.net/) for interactive table functionality
---
## Contact
For any questions or suggestions, please contact me via support {at} token2.com or open an issue in this repository.
+276
View File
@@ -0,0 +1,276 @@
<?php
// Configuration
$tenantId = 'xxx';
$clientId = 'xxx';
$clientSecret = 'xx';
$valid_username = 'admin'; // Set your username
$valid_password = 'P@ssword1'; // Set your password
session_start();
// Handle logout
if (isset($_GET['logout'])) {
session_destroy();
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
// Check if the user is already logged in
if (!isset($_SESSION['logged_in'])) {
// Check if form was submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// Validate credentials
if ($username === $valid_username && $password === $valid_password) {
$_SESSION['logged_in'] = true;
header('Location: ' . $_SERVER['PHP_SELF']); // Redirect to avoid form resubmission
exit;
} else {
$error_message = 'Invalid username or password';
}
}
// Show login form if not authenticated
echo '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link rel="stylesheet" href="assets/bootstrap.min.css">
</head>
<body>
<div class="container mt-4" style="max-width:600px">
<h2>Please Log In</h2><hr>
<form method="POST">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" id="username" name="username" class="form-control" required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="password" class="form-control" required>
</div>
' . (isset($error_message) ? '<p class="text-danger">' . htmlspecialchars($error_message) . '</p>' : '') . '
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</body>
</html>';
exit;
}
// Function to get an access token
function getAccessToken($tenantId, $clientId, $clientSecret) {
$url = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token";
$data = [
'grant_type' => 'client_credentials',
'client_id' => $clientId,
'client_secret' => $clientSecret,
'scope' => 'https://graph.microsoft.com/.default',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
$response = curl_exec($ch);
curl_close($ch);
$response = json_decode($response, true);
return $response['access_token'] ?? null;
}
// Function to fetch hardware tokens
function fetchHardwareTokens($accessToken) {
$url = "https://graph.microsoft.com/beta/directory/authenticationMethodDevices/hardwareOathDevices";
$headers = [
"Authorization: Bearer $accessToken",
"Content-Type: application/json",
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
$responseData = json_decode($response, true);
// Debugging: Save raw API response to debug.log
file_put_contents('debug.log', print_r($responseData, true));
return $responseData['value'] ?? [];
}
// Function to import tokens via PATCH
function importTokens($accessToken, $importData) {
$url = "https://graph.microsoft.com/beta/directory/authenticationMethodDevices/hardwareOathDevices";
$headers = [
"Authorization: Bearer $accessToken",
"Content-Type: application/json",
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($importData));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// Get Access Token
$accessToken = getAccessToken($tenantId, $clientId, $clientSecret);
if (!$accessToken) {
die('Failed to authenticate with Microsoft Graph.');
}
// Handle Import Action
$message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['importFile'])) {
$fileContent = file_get_contents($_FILES['importFile']['tmp_name']);
$importData = json_decode($fileContent, true);
if ($importData) {
$result = importTokens($accessToken, $importData);
$message = $result ? 'Tokens successfully imported!' : 'Failed to import tokens.';
} else {
$message = 'Invalid JSON file.';
}
}
// Fetch Hardware Tokens
$tokens = fetchHardwareTokens($accessToken);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hardware Token Management</title>
<link rel="stylesheet" href="assets/bootstrap.min.css">
<script src="assets/jquery-3.6.0.min.js"></script>
<script src="assets/jquery.dataTables.min.js"></script>
<script src="assets/dataTables.bootstrap4.min.js"></script>
<link rel="stylesheet" href="assets/dataTables.bootstrap4.min.css">
<script src="assets/bootstrap.min.js"></script>
<style>
.message { color: green; font-weight: bold; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="container mt-4">
<div class="float-right"
<!-- Import Button -->
<button type="button" class="btn btn-primary mb-3 mx-1 " data-toggle="modal" data-target="#importModal">
import tokens
</button>
<a href=?logout class="btn btn-secondary mb-3 " >
log out
</a>
</div>
<h5>Entra ID - Hardware token inventory portal</h5>
<?php if ($message): ?>
<p class="message"><?= htmlspecialchars($message) ?></p>
<?php endif; ?>
<br style="clear:both">
<!-- Import Modal -->
<div class="modal fade" id="importModal" tabindex="-1" role="dialog" aria-labelledby="importModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="importModalLabel">Import Tokens</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form method="POST" enctype="multipart/form-data">
<div class="form-group">
<label for="importFile">Upload JSON File:</label>
<input type="file" id="importFile" name="importFile" accept="application/json" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>
</div>
</div>
</div>
</div>
<table id="tokensTable" class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Serial Number</th>
<th>Device</th>
<th>User ID</th>
<th>Status</th>
<th>Last Updated</th>
</tr>
</thead>
<tbody>
<?php foreach ($tokens as $token): ?>
<tr>
<td><?= htmlspecialchars($token['serialNumber']) ?></td>
<td><?= htmlspecialchars($token['manufacturer']) ?> / <?= htmlspecialchars($token['model']) ?></td>
<td><?= htmlspecialchars($token['assignedTo']['displayName'] ?? 'Unassigned') ?></td>
<td><?= htmlspecialchars($token['status']) ?></td>
<td><?= htmlspecialchars($token['lastUsedDateTime'] ?? 'Never') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<script>
$(document).ready(function() {
$('#tokensTable').DataTable();
});
</script>
<br><br><hr>
<!-- Footer -->
<footer class="text-center text-lg-start bg-body-tertiary text-muted container mt-4">
<!-- Copyright -->
<div class="text-center p-4" style="background-color: rgba(0, 0, 0, 0.05);">
Created by
<a class="text-reset fw-bold" href="https://token2.swiss/">Token2 Sarl </a>
</div>
<!-- Copyright -->
</footer>
</body>
</html>