-
Notifications
You must be signed in to change notification settings - Fork 16
feat: integrate core service with SSO and GraphQL proxy updates #1875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2a31900
537f783
f73919a
9ddae2e
f83aa5c
9557998
84df97d
d77b2b7
8fdb128
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,7 +2,7 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php | |||||||||||||
| =================================================================== | ||||||||||||||
| --- /usr/local/emhttp/plugins/dynamix/include/.login.php original | ||||||||||||||
| +++ /usr/local/emhttp/plugins/dynamix/include/.login.php modified | ||||||||||||||
| @@ -1,6 +1,57 @@ | ||||||||||||||
| @@ -1,6 +1,76 @@ | ||||||||||||||
| <?php | ||||||||||||||
| + | ||||||||||||||
| + | ||||||||||||||
|
|
@@ -22,30 +22,49 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php | |||||||||||||
| + my_logger("SSO Login Attempt Failed: Invalid token format"); | ||||||||||||||
| + return false; | ||||||||||||||
| + } | ||||||||||||||
| + $safePassword = escapeshellarg($password); | ||||||||||||||
| + $payload = json_encode(["token" => $password]); | ||||||||||||||
| + $response = false; | ||||||||||||||
| + $code = 0; | ||||||||||||||
| + | ||||||||||||||
| + $output = array(); | ||||||||||||||
| + exec("/etc/rc.d/rc.unraid-api sso validate-token $safePassword 2>&1", $output, $code); | ||||||||||||||
| + if (function_exists("curl_init")) { | ||||||||||||||
| + $ch = curl_init("http://127.0.0.1/auth/sso/validate"); | ||||||||||||||
| + curl_setopt($ch, CURLOPT_POST, true); | ||||||||||||||
| + curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]); | ||||||||||||||
| + curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); | ||||||||||||||
| + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||||||||||||||
| + curl_setopt($ch, CURLOPT_TIMEOUT, 5); | ||||||||||||||
| + $response = curl_exec($ch); | ||||||||||||||
| + $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); | ||||||||||||||
| + curl_close($ch); | ||||||||||||||
| + } else { | ||||||||||||||
| + $context = stream_context_create([ | ||||||||||||||
| + "http" => [ | ||||||||||||||
| + "method" => "POST", | ||||||||||||||
| + "header" => "Content-Type: application/json | ||||||||||||||
| +", | ||||||||||||||
| + "content" => $payload, | ||||||||||||||
| + "timeout" => 5, | ||||||||||||||
| + ], | ||||||||||||||
| + ]); | ||||||||||||||
| + $response = @file_get_contents("http://127.0.0.1/auth/sso/validate", false, $context); | ||||||||||||||
| + if (isset($http_response_header[0])) { | ||||||||||||||
| + $code = (int) preg_replace('/^HTTP\/[0-9.]+\s+(\d+).*/', '', $http_response_header[0]); | ||||||||||||||
| + } | ||||||||||||||
|
Comment on lines
+50
to
+52
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HTTP status code extraction returns empty string instead of the status code. The 🐛 Proposed fix if (isset($http_response_header[0])) {
- $code = (int) preg_replace('/^HTTP\/[0-9.]+\s+(\d+).*/', '', $http_response_header[0]);
+ $code = (int) preg_replace('/^HTTP\/[0-9.]+\s+(\d+).*/', '$1', $http_response_header[0]);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| + } | ||||||||||||||
| + my_logger("SSO Login Attempt Code: $code"); | ||||||||||||||
| + my_logger("SSO Login Attempt Response: " . print_r($output, true)); | ||||||||||||||
| + my_logger("SSO Login Attempt Response: " . print_r($response, true)); | ||||||||||||||
| + | ||||||||||||||
| + if ($code !== 0) { | ||||||||||||||
| + if ($code !== 200) { | ||||||||||||||
| + return false; | ||||||||||||||
| + } | ||||||||||||||
| + | ||||||||||||||
| + if (empty($output)) { | ||||||||||||||
| + if (empty($response)) { | ||||||||||||||
| + return false; | ||||||||||||||
| + } | ||||||||||||||
| + | ||||||||||||||
| + try { | ||||||||||||||
| + // Split on first { and take everything after it | ||||||||||||||
| + $jsonParts = explode('{', $output[0], 2); | ||||||||||||||
| + if (count($jsonParts) < 2) { | ||||||||||||||
| + my_logger("SSO Login Attempt Failed: No JSON found in response"); | ||||||||||||||
| + return false; | ||||||||||||||
| + } | ||||||||||||||
| + $response = json_decode('{' . $jsonParts[1], true); | ||||||||||||||
| + if (isset($response['valid']) && $response['valid'] === true) { | ||||||||||||||
| + $decoded = json_decode($response, true); | ||||||||||||||
| + if (isset($decoded['valid']) && $decoded['valid'] === true) { | ||||||||||||||
| + return true; | ||||||||||||||
| + } | ||||||||||||||
| + } catch (Exception $e) { | ||||||||||||||
|
|
@@ -60,7 +79,7 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php | |||||||||||||
| // Only start a session to check if they have a cookie that looks like our session | ||||||||||||||
| $server_name = strtok($_SERVER['HTTP_HOST'], ":"); | ||||||||||||||
| if (!empty($_COOKIE['unraid_'.md5($server_name)])) { | ||||||||||||||
| @@ -128,11 +179,11 @@ | ||||||||||||||
| @@ -128,11 +198,11 @@ | ||||||||||||||
| } | ||||||||||||||
| throw new Exception(_('Too many invalid login attempts')); | ||||||||||||||
| } | ||||||||||||||
|
|
@@ -73,7 +92,7 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php | |||||||||||||
|
|
||||||||||||||
| // Successful login, start session | ||||||||||||||
| @unlink($failFile); | ||||||||||||||
| @@ -434,10 +485,11 @@ | ||||||||||||||
| @@ -434,10 +504,11 @@ | ||||||||||||||
| </p> | ||||||||||||||
| <?php if ($error) { ?> | ||||||||||||||
| <p class="error"><?= $error ?></p> | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,9 +7,11 @@ import { | |
| } from '@app/unraid-api/unraid-file-modifier/file-modification.js'; | ||
|
|
||
| /** | ||
| * Patch rc.nginx on < Unraid 7.2.0 to read the updated connect & api config files | ||
| * Patch rc.nginx to read the updated connect & api config files. | ||
| * | ||
| * Backport of https://github.com/unraid/webgui/pull/2269 | ||
| * Backport of https://github.com/unraid/webgui/pull/2269. This modification | ||
| * runs on all versions but uses idempotent guards to avoid double-injection | ||
| * when the base OS already includes the changes. | ||
| */ | ||
| export default class RcNginxModification extends FileModification { | ||
| public filePath: string = '/etc/rc.d/rc.nginx' as const; | ||
|
|
@@ -29,9 +31,9 @@ export default class RcNginxModification extends FileModification { | |
| throw new Error(`File ${this.filePath} not found.`); | ||
| } | ||
| const fileContent = await readFile(this.filePath, 'utf8'); | ||
| if (!fileContent.includes('MYSERVERS=')) { | ||
| throw new Error(`MYSERVERS not found in the file; incorrect target?`); | ||
| } | ||
| // if (!fileContent.includes('MYSERVERS=')) { | ||
| // throw new Error(`MYSERVERS not found in the file; incorrect target?`); | ||
| // } | ||
|
|
||
| let newContent = fileContent.replace( | ||
| 'MYSERVERS="/boot/config/plugins/dynamix.my.servers/myservers.cfg"', | ||
|
|
@@ -68,6 +70,27 @@ check_remote_access(){ | |
| `if [[ -L /usr/local/sbin/unraid-api ]] && check_remote_access; then` | ||
| ); | ||
|
|
||
| newContent = newContent.replace( | ||
| 'proxy_pass http://unix:/var/run/unraid-api.sock:/graphql;', | ||
| 'if ($http_upgrade = "websocket") {\n\t rewrite ^/graphql$ /graphql/socket break;\n\t }\n\t proxy_pass http://unix:/var/run/unraid-core.sock:;' | ||
| ); | ||
|
|
||
| if (!newContent.includes('location /auth/sso')) { | ||
| newContent = newContent.replace( | ||
| '\t# Redirect to login page on failed authentication (401)\n', | ||
| // prettier-ignore | ||
| `\t# SSO endpoints (public)\n\tlocation /auth/sso {\n\t allow all;\n\t proxy_pass http://unix:/var/run/unraid-core.sock:;\n\t proxy_http_version 1.1;\n\t proxy_set_header Host $host;\n\t proxy_set_header X-Real-IP $remote_addr;\n\t proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\t proxy_set_header X-Forwarded-Proto $scheme;\n\t}\n\t#\n\t# Redirect to login page on failed authentication (401)\n` | ||
| ); | ||
| } | ||
|
|
||
| if (!newContent.includes('location /graphql/api/auth/oidc')) { | ||
| newContent = newContent.replace( | ||
| '\t# my servers proxy\n\t#\n\tlocation /graphql {', | ||
| // prettier-ignore | ||
| `\t# my servers proxy\n\t#\n\tlocation /graphql/api/auth/oidc {\n\t allow all;\n\t proxy_pass http://unix:/var/run/unraid-core.sock:;\n\t proxy_http_version 1.1;\n\t proxy_set_header Host $host;\n\t proxy_set_header X-Real-IP $remote_addr;\n\t proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\t proxy_set_header X-Forwarded-Proto $scheme;\n\t}\n\tlocation /graphql/api {\n\t allow all;\n\t proxy_pass http://unix:/var/run/unraid-api.sock:;\n\t proxy_http_version 1.1;\n\t proxy_set_header Host $host;\n\t proxy_set_header X-Real-IP $remote_addr;\n\t proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\t proxy_set_header X-Forwarded-Proto $scheme;\n\t}\n\tlocation /graphql {` | ||
| ); | ||
| } | ||
|
|
||
| newContent = newContent.replace( | ||
| 'for NET in ${!NET_FQDN6[@]}; do', | ||
| 'for NET in "${!NET_FQDN6[@]}"; do' | ||
|
|
@@ -91,7 +114,7 @@ check_remote_access(){ | |
| } | ||
|
|
||
| async shouldApply(): Promise<ShouldApplyWithReason> { | ||
| const { shouldApply, reason } = await super.shouldApply(); | ||
| const { shouldApply, reason } = await super.shouldApply({ checkOsVersion: false }); | ||
| return { | ||
|
Comment on lines
116
to
118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
By forcing Useful? React with 👍 / 👎. |
||
| shouldApply, | ||
| reason, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Snapshot contains incorrect preg_replace replacement string.
Same issue as the patch file - uses
''instead of'$1'. Regenerate this snapshot after fixing the source.🤖 Prompt for AI Agents