diff --git a/install/config/config.php b/install/config/config.php
index 1e4ad582d..71c65a986 100644
--- a/install/config/config.php
+++ b/install/config/config.php
@@ -100,6 +100,11 @@ $config['qrzru_password'] = '%qrzru_password%';
| 'auth_mode' Minimum user level required 0 = anonymous, 1 = viewer,
| 2 = editor, 3 = api user, 99 = owner
| 'auth_level[]' Defines level titles
+|
+| 'auth_header_enable' False disables header based authentication
+| 'auth_header_create' False disables user creation if user doesn't exist
+| 'auth_header_value' Which header provides authenticated username
+| 'auth_header_text' Display text on login screen
*/
$config['use_auth'] = true;
@@ -109,6 +114,11 @@ $config['auth_mode'] = '3';
$config['auth_level'][3] = 'Operator';
$config['auth_level'][99] = 'Administrator';
+$config['auth_header_enable'] = false;
+$config['auth_header_create'] = false;
+$config['auth_header_value'] = "HTTP_X-Username";
+$config['auth_header_text'] = "Login with SSO";
+
/*
|--------------------------------------------------------------------------
| Base Site URL
From 8027474f2d03c5eed1b0042e32865934d2fdfc8d Mon Sep 17 00:00:00 2001
From: HadleySo <71105018+HadleySo@users.noreply.github.com>
Date: Wed, 18 Feb 2026 21:46:44 -0600
Subject: [PATCH 02/48] Adding user creation with club memebership
---
application/config/config.sample.php | 2 +
application/controllers/Header_auth.php | 51 ++++++++++++++++-
application/models/User_model.php | 76 +++++++++++++++++++++++++
install/config/config.php | 2 +
4 files changed, 128 insertions(+), 3 deletions(-)
diff --git a/application/config/config.sample.php b/application/config/config.sample.php
index db8660972..b387eeeae 100644
--- a/application/config/config.sample.php
+++ b/application/config/config.sample.php
@@ -105,6 +105,7 @@ $config['qrzru_password'] = '';
| 'auth_header_create' False disables user creation if user doesn't exist
| 'auth_header_value' Which header provides authenticated username
| 'auth_header_text' Display text on login screen
+| 'auth_header_club_id' Default club ID to add new users to
*/
$config['use_auth'] = true;
@@ -118,6 +119,7 @@ $config['auth_header_enable'] = false;
$config['auth_header_create'] = false;
$config['auth_header_value'] = "HTTP_X-Username";
$config['auth_header_text'] = "Login with SSO";
+$config['auth_header_club_id'] = "";
/*
|--------------------------------------------------------------------------
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 8037cc16f..a00f326b4 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -43,10 +43,33 @@ class Header_auth extends CI_Controller
// Look up user by the header value
$query = $this->user_model->get($username);
if (!$query || $query->num_rows() !== 1) {
- $this->session->set_flashdata('error', __('User not found.'));
- redirect('user/login');
+
+ // Config check if create user
+ if ($this->config->item('auth_header_create')) {
+ $this->load->model('user_model');
+ $club_id = $this->config->item('auth_header_club_id');
+ $result = $this->user_model->add_minimal(username: $username, club_id: $club_id);
+
+ switch ($result) {
+ case EUSERNAMEEXISTS:
+ $data['username_error'] = sprintf(__("Username %s already in use!"), '
' . $this->input->post('user_name') . '');
+ break;
+ case EEMAILEXISTS:
+ $data['email_error'] = sprintf(__("E-mail %s already in use!"), '
' . $this->input->post('user_email') . '');
+ break;
+ case EPASSWORDINVALID:
+ $data['password_error'] = __("Invalid Password!");
+ break;
+ case OK:
+ redirect('header_auth/login');
+ return;
+ }
+ } else {
+ $this->session->set_flashdata('error', __('User not found.'));
+ redirect('user/login');
+ }
}
-
+
$user = $query->row();
@@ -75,6 +98,28 @@ class Header_auth extends CI_Controller
];
$this->input->set_cookie($cookie);
+ $this->load->model('user_model');
+ // Get full user record
+ $user = $this->user_model->get($username)->row();
+
+ // Critical: Update session data
+ $this->user_model->update_session($user->user_id);
+ $this->user_model->set_last_seen($user->user_id);
+
+ // Set essential session data
+ $this->session->set_userdata(array(
+ 'user_id' => $user->user_id,
+ 'user_name' => $user->user_name,
+ 'user_type' => $user->user_type,
+ 'user_stylesheet' => $user->user_stylesheet ?? 'bootstrap',
+ 'user_column1' => $user->user_column1 ?? 'Mode',
+ 'user_column2' => $user->user_column2 ?? 'RSTS',
+ 'user_column3' => $user->user_column3 ?? 'RSTR',
+ 'user_column4' => $user->user_column4 ?? 'Band',
+ 'user_column5' => $user->user_column5 ?? 'Country',
+ // Add other preferences as needed
+ ));
+
log_message('info', "User ID [{$user->user_id}] logged in via header auth.");
redirect('dashboard');
}
diff --git a/application/models/User_model.php b/application/models/User_model.php
index 34385a7e6..8c9e66da4 100644
--- a/application/models/User_model.php
+++ b/application/models/User_model.php
@@ -323,6 +323,82 @@ class User_Model extends CI_Model {
}
}
+ /**
+ * FUNCTION: bool add_minimal($username, $firstname = null, $lastname = null, $callsign = null, $email = null, $club_id = null)
+ * Add a user with minimal required fields (username only) with option to add to club as user
+ */
+ function add_minimal($username, $firstname = null, $lastname = null, $callsign = null, $email = null, $club_id = null) {
+ // Check that the username isn't already used
+ if(!$this->exists($username)) {
+ $data = array(
+ 'user_name' => xss_clean($username),
+ 'user_password' => bin2hex(random_bytes(16)), // Random password
+ 'user_email' => xss_clean($email) ?? '',
+ 'user_firstname' => xss_clean($firstname) ?? '',
+ 'user_lastname' => xss_clean($lastname) ?? '',
+ 'user_callsign' => strtoupper(xss_clean($callsign)) ?? '',
+ 'user_type' => 3,
+ 'user_locator' => '',
+ 'user_stylesheet' => 'darkly',
+ 'user_language' => 'english',
+ 'user_timezone' => '1',
+ 'user_date_format' => 'd/m/y',
+ 'user_measurement_base' => 'M',
+ 'user_column1' => 'Mode',
+ 'user_column2' => 'RSTS',
+ 'user_column3' => 'RSTR',
+ 'user_column4' => 'Band',
+ 'user_column5' => 'Country',
+ 'user_qso_end_times' => 0,
+ 'user_show_profile_image' => 0,
+ 'user_qth_lookup' => 0,
+ 'user_sota_lookup' => 0,
+ 'user_wwff_lookup' => 0,
+ 'user_pota_lookup' => 0,
+ 'user_show_notes' => 0,
+ 'user_quicklog' => 0,
+ 'user_quicklog_enter' => 0,
+ 'user_previous_qsl_type' => 0,
+ 'user_default_band' => 'All',
+ 'user_lotw_name' => '',
+ 'user_lotw_password' => '',
+ 'user_eqsl_name' => '',
+ 'user_eqsl_password' => '',
+ 'user_clublog_name' => '',
+ 'user_clublog_password' => '',
+ 'user_amsat_status_upload' => 0,
+ 'user_mastodon_url' => '',
+ );
+
+ // Check the email address isn't in use (if provided)
+ if($email && $this->exists_by_email($email)) {
+ return EEMAILEXISTS;
+ }
+
+ // Generate user-slug
+ if (!$this->load->is_loaded('encryption')) {
+ $this->load->library('encryption');
+ }
+ $user_slug_base = md5($this->encryption->encrypt($username));
+ $user_slug = substr($user_slug_base, 0, USER_SLUG_LENGTH);
+ $data['slug'] = $user_slug;
+
+ // Add user
+ $this->db->insert($this->config->item('auth_table'), $data);
+ $insert_id = $this->db->insert_id();
+
+ // Add user to club
+ if ($club_id && is_numeric($club_id)) {
+ $this->load->model('club_model');
+ $this->club_model->alter_member($club_id, $insert_id, 3);
+ }
+
+ return OK;
+ } else {
+ return EUSERNAMEEXISTS;
+ }
+ }
+
// FUNCTION: bool edit()
// Edit a user
function edit($fields) {
diff --git a/install/config/config.php b/install/config/config.php
index 71c65a986..e90ff13da 100644
--- a/install/config/config.php
+++ b/install/config/config.php
@@ -105,6 +105,7 @@ $config['qrzru_password'] = '%qrzru_password%';
| 'auth_header_create' False disables user creation if user doesn't exist
| 'auth_header_value' Which header provides authenticated username
| 'auth_header_text' Display text on login screen
+| 'auth_header_club_id' Default club ID to add new users to
*/
$config['use_auth'] = true;
@@ -118,6 +119,7 @@ $config['auth_header_enable'] = false;
$config['auth_header_create'] = false;
$config['auth_header_value'] = "HTTP_X-Username";
$config['auth_header_text'] = "Login with SSO";
+$config['auth_header_club_id'] = "";
/*
|--------------------------------------------------------------------------
From 7ffc4b87733da104646819967c5297aa6d58af80 Mon Sep 17 00:00:00 2001
From: HadleySo <71105018+HadleySo@users.noreply.github.com>
Date: Wed, 18 Feb 2026 22:20:33 -0600
Subject: [PATCH 03/48] Adding config for name, callsign, and email
---
application/config/config.sample.php | 20 ++++++++++++-----
application/controllers/Header_auth.php | 30 ++++++++++++++++++++-----
install/config/config.php | 20 ++++++++++++-----
3 files changed, 53 insertions(+), 17 deletions(-)
diff --git a/application/config/config.sample.php b/application/config/config.sample.php
index b387eeeae..9bf39420b 100644
--- a/application/config/config.sample.php
+++ b/application/config/config.sample.php
@@ -101,11 +101,15 @@ $config['qrzru_password'] = '';
| 2 = editor, 3 = api user, 99 = owner
| 'auth_level[]' Defines level titles
|
-| 'auth_header_enable' False disables header based authentication
-| 'auth_header_create' False disables user creation if user doesn't exist
-| 'auth_header_value' Which header provides authenticated username
-| 'auth_header_text' Display text on login screen
-| 'auth_header_club_id' Default club ID to add new users to
+| 'auth_header_enable' False disables header based authentication
+| 'auth_header_create' False disables user creation for header based authentication
+| 'auth_headers_username' Which header provides authenticated username
+| 'auth_headers_firstname' Which header provides authenticated first name
+| 'auth_headers_lastname' Which header provides authenticated last name
+| 'auth_headers_callsign' Which header provides authenticated callsign
+| 'auth_headers_email' Which header provides authenticated email
+| 'auth_header_text' Display text on login screen
+| 'auth_header_club_id' Default club ID to add new users to
*/
$config['use_auth'] = true;
@@ -117,7 +121,11 @@ $config['auth_level'][99] = 'Administrator';
$config['auth_header_enable'] = false;
$config['auth_header_create'] = false;
-$config['auth_header_value'] = "HTTP_X-Username";
+$config['auth_headers_username'] = "HTTP_X-Username";
+$config['auth_headers_firstname'] = null;
+$config['auth_headers_lastname'] = null;
+$config['auth_headers_callsign'] = null;
+$config['auth_headers_email'] = null;
$config['auth_header_text'] = "Login with SSO";
$config['auth_header_club_id'] = "";
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index a00f326b4..11f843b9e 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -28,12 +28,14 @@ class Header_auth extends CI_Controller
redirect('user/login');
}
- $headerName = $this->config->item('auth_header_value') ?: '';
- if (empty($headerName)) {
+
+ // Get username from header
+ $headerUsername = $this->config->item('auth_headers_username') ?: '';
+ if (empty($headerUsername)) {
$this->session->set_flashdata('error', __('Missing header setting.'));
redirect('user/login');
}
- $username = $this->input->server($headerName, true);
+ $username = $this->input->server($headerUsername, true);
if (empty($username)) {
$this->session->set_flashdata('error', __('Missing username header.'));
@@ -47,8 +49,26 @@ class Header_auth extends CI_Controller
// Config check if create user
if ($this->config->item('auth_header_create')) {
$this->load->model('user_model');
- $club_id = $this->config->item('auth_header_club_id');
- $result = $this->user_model->add_minimal(username: $username, club_id: $club_id);
+ $firstnameHeader = $this->config->item('auth_headers_firstname') ?: '';
+ if (!empty($firstnameHeader)) {
+ $firstname = $this->input->server($firstnameHeader, true);
+ }
+ $lastnameHeader = $this->config->item('auth_headers_lastname') ?: '';
+ if (!empty($lastnameHeader)) {
+ $lastname = $this->input->server($lastnameHeader, true);
+ }
+ $callsignHeader = $this->config->item('auth_headers_callsign') ?: '';
+ if (!empty($callsignHeader)) {
+ $callsign = $this->input->server($callsignHeader, true);
+ }
+ $emailHeader = $this->config->item('auth_headers_email') ?: '';
+ if (!empty($emailHeader)) {
+ $email = $this->input->server($emailHeader, true);
+ }
+
+ $club_id = $this->config->item('auth_header_club_id') ?: '';
+
+ $result = $this->user_model->add_minimal($username, $firstname, $lastname, $callsign, $email, $club_id);
switch ($result) {
case EUSERNAMEEXISTS:
diff --git a/install/config/config.php b/install/config/config.php
index e90ff13da..7478c8f8f 100644
--- a/install/config/config.php
+++ b/install/config/config.php
@@ -101,11 +101,15 @@ $config['qrzru_password'] = '%qrzru_password%';
| 2 = editor, 3 = api user, 99 = owner
| 'auth_level[]' Defines level titles
|
-| 'auth_header_enable' False disables header based authentication
-| 'auth_header_create' False disables user creation if user doesn't exist
-| 'auth_header_value' Which header provides authenticated username
-| 'auth_header_text' Display text on login screen
-| 'auth_header_club_id' Default club ID to add new users to
+| 'auth_header_enable' False disables header based authentication
+| 'auth_header_create' False disables user creation for header based authentication
+| 'auth_headers_username' Which header provides authenticated username
+| 'auth_headers_firstname' Which header provides authenticated first name
+| 'auth_headers_lastname' Which header provides authenticated last name
+| 'auth_headers_callsign' Which header provides authenticated callsign
+| 'auth_headers_email' Which header provides authenticated email
+| 'auth_header_text' Display text on login screen
+| 'auth_header_club_id' Default club ID to add new users to
*/
$config['use_auth'] = true;
@@ -117,7 +121,11 @@ $config['auth_level'][99] = 'Administrator';
$config['auth_header_enable'] = false;
$config['auth_header_create'] = false;
-$config['auth_header_value'] = "HTTP_X-Username";
+$config['auth_headers_username'] = "HTTP_X-Username";
+$config['auth_headers_firstname'] = null;
+$config['auth_headers_lastname'] = null;
+$config['auth_headers_callsign'] = null;
+$config['auth_headers_email'] = null;
$config['auth_header_text'] = "Login with SSO";
$config['auth_header_club_id'] = "";
From a8560275749144b7e7021ff44a08f554eb1a506d Mon Sep 17 00:00:00 2001
From: HadleySo <71105018+HadleySo@users.noreply.github.com>
Date: Sat, 21 Feb 2026 12:50:37 -0600
Subject: [PATCH 04/48] Partial rollback
8027474f2d03c5eed1b0042e32865934d2fdfc8d remove User_model::add_minimal()
---
application/controllers/Header_auth.php | 73 +++++++++++++++++++++++-
application/models/User_model.php | 76 -------------------------
2 files changed, 72 insertions(+), 77 deletions(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 11f843b9e..08e688416 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -52,23 +52,94 @@ class Header_auth extends CI_Controller
$firstnameHeader = $this->config->item('auth_headers_firstname') ?: '';
if (!empty($firstnameHeader)) {
$firstname = $this->input->server($firstnameHeader, true);
+ } else {
+ $firstname = '';
}
$lastnameHeader = $this->config->item('auth_headers_lastname') ?: '';
if (!empty($lastnameHeader)) {
$lastname = $this->input->server($lastnameHeader, true);
+ } else {
+ $lastname = '';
}
$callsignHeader = $this->config->item('auth_headers_callsign') ?: '';
if (!empty($callsignHeader)) {
$callsign = $this->input->server($callsignHeader, true);
+ } else {
+ $callsign = '';
}
$emailHeader = $this->config->item('auth_headers_email') ?: '';
if (!empty($emailHeader)) {
$email = $this->input->server($emailHeader, true);
+ } else {
+ $email = '';
}
$club_id = $this->config->item('auth_header_club_id') ?: '';
- $result = $this->user_model->add_minimal($username, $firstname, $lastname, $callsign, $email, $club_id);
+ $result = $this->user_model->add(
+ $username,
+ bin2hex(random_bytes(16)), // password
+ $email,
+ 3, // $data['user_type'], Anlage auf 3
+ $firstname,
+ $lastname,
+ $callsign,
+ "", // locator
+ 102, // user_timezone
+ "M", // measurement
+ "Y", // dashboard_map
+ "Y-m-d", // user_date_format
+ 'darkly', // user_stylesheet
+ '0', // user_qth_lookup
+ '0', // user_sota_lookup
+ '0', // user_wwff_lookup
+ '0', // user_pota_lookup
+ 1, // user_show_notes
+ 'Mode', // user_column1
+ 'RSTS', // user_column2
+ 'RSTR', // user_column3
+ 'Band', // user_column4
+ 'Country', // user_column5
+ '0', // user_show_profile_image
+ '0', // user_previous_qsl_type
+ '0', // user_amsat_status_upload
+ '', // user_mastodon_url
+ 'ALL', // user_default_band
+ 'QL', // user_default_confirmation
+ '0', // user_qso_end_times
+ "Y", // user_qso_db_search_priority
+ '0', // user_quicklog
+ '0', // user_quicklog_enter
+ "en", // user_language
+ '', // user_hamsat_key
+ '', // user_hamsat_workable_only
+ '', // user_iota_to_qso_tab
+ '', // user_sota_to_qso_tab
+ '', // user_wwff_to_qso_tab
+ '', // user_pota_to_qso_tab
+ '', // user_sig_to_qso_tab
+ '', // user_dok_to_qso_tab
+ 0, // user_station_to_qso_tab
+ '', // user_lotw_name
+ '', // user_lotw_password
+ '', // user_eqsl_name
+ '', // user_eqsl_password
+ '', // user_clublog_name
+ '', // user_clublog_password
+ '0', // user_winkey
+ "", // on_air_widget_enabled
+ "", // on_air_widget_display_last_seen
+ "", // on_air_widget_show_only_most_recent_radio
+ "", // qso_widget_display_qso_time
+ "", // dashboard_banner
+ "", // dashboard_solar
+ "", // global_oqrs_text
+ "", // oqrs_grouped_search
+ "", // oqrs_grouped_search_show_station_name
+ "", // oqrs_auto_matching
+ "", // oqrs_direct_auto_matching
+ "", // user_dxwaterfall_enable
+ );
switch ($result) {
case EUSERNAMEEXISTS:
diff --git a/application/models/User_model.php b/application/models/User_model.php
index 8c9e66da4..34385a7e6 100644
--- a/application/models/User_model.php
+++ b/application/models/User_model.php
@@ -323,82 +323,6 @@ class User_Model extends CI_Model {
}
}
- /**
- * FUNCTION: bool add_minimal($username, $firstname = null, $lastname = null, $callsign = null, $email = null, $club_id = null)
- * Add a user with minimal required fields (username only) with option to add to club as user
- */
- function add_minimal($username, $firstname = null, $lastname = null, $callsign = null, $email = null, $club_id = null) {
- // Check that the username isn't already used
- if(!$this->exists($username)) {
- $data = array(
- 'user_name' => xss_clean($username),
- 'user_password' => bin2hex(random_bytes(16)), // Random password
- 'user_email' => xss_clean($email) ?? '',
- 'user_firstname' => xss_clean($firstname) ?? '',
- 'user_lastname' => xss_clean($lastname) ?? '',
- 'user_callsign' => strtoupper(xss_clean($callsign)) ?? '',
- 'user_type' => 3,
- 'user_locator' => '',
- 'user_stylesheet' => 'darkly',
- 'user_language' => 'english',
- 'user_timezone' => '1',
- 'user_date_format' => 'd/m/y',
- 'user_measurement_base' => 'M',
- 'user_column1' => 'Mode',
- 'user_column2' => 'RSTS',
- 'user_column3' => 'RSTR',
- 'user_column4' => 'Band',
- 'user_column5' => 'Country',
- 'user_qso_end_times' => 0,
- 'user_show_profile_image' => 0,
- 'user_qth_lookup' => 0,
- 'user_sota_lookup' => 0,
- 'user_wwff_lookup' => 0,
- 'user_pota_lookup' => 0,
- 'user_show_notes' => 0,
- 'user_quicklog' => 0,
- 'user_quicklog_enter' => 0,
- 'user_previous_qsl_type' => 0,
- 'user_default_band' => 'All',
- 'user_lotw_name' => '',
- 'user_lotw_password' => '',
- 'user_eqsl_name' => '',
- 'user_eqsl_password' => '',
- 'user_clublog_name' => '',
- 'user_clublog_password' => '',
- 'user_amsat_status_upload' => 0,
- 'user_mastodon_url' => '',
- );
-
- // Check the email address isn't in use (if provided)
- if($email && $this->exists_by_email($email)) {
- return EEMAILEXISTS;
- }
-
- // Generate user-slug
- if (!$this->load->is_loaded('encryption')) {
- $this->load->library('encryption');
- }
- $user_slug_base = md5($this->encryption->encrypt($username));
- $user_slug = substr($user_slug_base, 0, USER_SLUG_LENGTH);
- $data['slug'] = $user_slug;
-
- // Add user
- $this->db->insert($this->config->item('auth_table'), $data);
- $insert_id = $this->db->insert_id();
-
- // Add user to club
- if ($club_id && is_numeric($club_id)) {
- $this->load->model('club_model');
- $this->club_model->alter_member($club_id, $insert_id, 3);
- }
-
- return OK;
- } else {
- return EUSERNAMEEXISTS;
- }
- }
-
// FUNCTION: bool edit()
// Edit a user
function edit($fields) {
From e0f0dd3a049d0665b7d8605bff3cb2689bc7960f Mon Sep 17 00:00:00 2001
From: HadleySo <71105018+HadleySo@users.noreply.github.com>
Date: Sat, 21 Feb 2026 14:09:52 -0600
Subject: [PATCH 05/48] Random password to 512 bit
---
application/controllers/Header_auth.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 08e688416..e8516eb3a 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -78,7 +78,7 @@ class Header_auth extends CI_Controller
$result = $this->user_model->add(
$username,
- bin2hex(random_bytes(16)), // password
+ bin2hex(random_bytes(64)), // password
$email,
3, // $data['user_type'], Anlage auf 3
$firstname,
From 632990b7f7faed748f629794bb2d31addcae68fb Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 11:46:59 +0100
Subject: [PATCH 06/48] fix formatting (using k&r for braces)
---
application/controllers/Header_auth.php | 43 ++++++++++++-------------
1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index e8516eb3a..7052f1063 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -5,11 +5,9 @@
Handles header based authentication
*/
-class Header_auth extends CI_Controller
-{
+class Header_auth extends CI_Controller {
- public function __construct()
- {
+ public function __construct() {
parent::__construct();
$this->load->model('user_model');
$this->load->library('session');
@@ -20,8 +18,7 @@ class Header_auth extends CI_Controller
* Authenticate using a trusted request header.
* Expected to be called from a login-screen button.
*/
- public function login()
- {
+ public function login() {
// Guard: feature must be enabled
if (!$this->config->item('auth_header_enable')) {
$this->session->set_flashdata('error', __('Header authentication is disabled.'));
@@ -80,7 +77,7 @@ class Header_auth extends CI_Controller
$username,
bin2hex(random_bytes(64)), // password
$email,
- 3, // $data['user_type'], Anlage auf 3
+ 3, // $data['user_type'], Anlage auf 3
$firstname,
$lastname,
$callsign,
@@ -140,7 +137,7 @@ class Header_auth extends CI_Controller
"", // oqrs_direct_auto_matching
"", // user_dxwaterfall_enable
);
-
+
switch ($result) {
case EUSERNAMEEXISTS:
$data['username_error'] = sprintf(__("Username %s already in use!"), '' . $this->input->post('user_name') . '');
@@ -189,25 +186,25 @@ class Header_auth extends CI_Controller
];
$this->input->set_cookie($cookie);
- $this->load->model('user_model');
+ $this->load->model('user_model');
// Get full user record
- $user = $this->user_model->get($username)->row();
-
+ $user = $this->user_model->get($username)->row();
+
// Critical: Update session data
- $this->user_model->update_session($user->user_id);
- $this->user_model->set_last_seen($user->user_id);
+ $this->user_model->update_session($user->user_id);
+ $this->user_model->set_last_seen($user->user_id);
// Set essential session data
- $this->session->set_userdata(array(
- 'user_id' => $user->user_id,
- 'user_name' => $user->user_name,
- 'user_type' => $user->user_type,
- 'user_stylesheet' => $user->user_stylesheet ?? 'bootstrap',
- 'user_column1' => $user->user_column1 ?? 'Mode',
- 'user_column2' => $user->user_column2 ?? 'RSTS',
- 'user_column3' => $user->user_column3 ?? 'RSTR',
- 'user_column4' => $user->user_column4 ?? 'Band',
- 'user_column5' => $user->user_column5 ?? 'Country',
+ $this->session->set_userdata(array(
+ 'user_id' => $user->user_id,
+ 'user_name' => $user->user_name,
+ 'user_type' => $user->user_type,
+ 'user_stylesheet' => $user->user_stylesheet ?? 'bootstrap',
+ 'user_column1' => $user->user_column1 ?? 'Mode',
+ 'user_column2' => $user->user_column2 ?? 'RSTS',
+ 'user_column3' => $user->user_column3 ?? 'RSTR',
+ 'user_column4' => $user->user_column4 ?? 'Band',
+ 'user_column5' => $user->user_column5 ?? 'Country',
// Add other preferences as needed
));
From 852de9ef9dfa92728fc625d78567969cdaf7c6a6 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 12:38:01 +0100
Subject: [PATCH 07/48] catch missing callsign and email header data as those
values are required for a user creation
---
application/controllers/Header_auth.php | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 7052f1063..638f50baa 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -62,13 +62,15 @@ class Header_auth extends CI_Controller {
if (!empty($callsignHeader)) {
$callsign = $this->input->server($callsignHeader, true);
} else {
- $callsign = '';
+ $this->session->set_flashdata('error', __('Missing callsign header.'));
+ redirect('user/login');
}
$emailHeader = $this->config->item('auth_headers_email') ?: '';
if (!empty($emailHeader)) {
$email = $this->input->server($emailHeader, true);
} else {
- $email = '';
+ $this->session->set_flashdata('error', __('Missing email header.'));
+ redirect('user/login');
}
$club_id = $this->config->item('auth_header_club_id') ?: '';
From c3337d0fda9cbf98b5d83fde8508dafb9f530d41 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 12:42:20 +0100
Subject: [PATCH 08/48] default user timezone should be utc
---
application/controllers/Header_auth.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 638f50baa..5dd4b5d25 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -84,7 +84,7 @@ class Header_auth extends CI_Controller {
$lastname,
$callsign,
"", // locator
- 102, // user_timezone
+ 24, // user_timezone is default UTC
"M", // measurement
"Y", // dashboard_map
"Y-m-d", // user_date_format
From 5b717f3ae22f77ea99375ad16716d70b43231076 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 12:43:44 +0100
Subject: [PATCH 09/48] fix user language
---
application/controllers/Header_auth.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 5dd4b5d25..25bf464d8 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -109,7 +109,7 @@ class Header_auth extends CI_Controller {
"Y", // user_qso_db_search_priority
'0', // user_quicklog
'0', // user_quicklog_enter
- "en", // user_language
+ "english", // user_language
'', // user_hamsat_key
'', // user_hamsat_workable_only
'', // user_iota_to_qso_tab
From 94e791b9cb097b0309151144c1525a97eb37b9df Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 12:45:39 +0100
Subject: [PATCH 10/48] prevent loading user_model multiple times
---
application/controllers/Header_auth.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 25bf464d8..8a67f63d4 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -45,7 +45,6 @@ class Header_auth extends CI_Controller {
// Config check if create user
if ($this->config->item('auth_header_create')) {
- $this->load->model('user_model');
$firstnameHeader = $this->config->item('auth_headers_firstname') ?: '';
if (!empty($firstnameHeader)) {
$firstname = $this->input->server($firstnameHeader, true);
@@ -188,7 +187,6 @@ class Header_auth extends CI_Controller {
];
$this->input->set_cookie($cookie);
- $this->load->model('user_model');
// Get full user record
$user = $this->user_model->get($username)->row();
From 20a8fe5bd45a38249528052925ff141931e656db Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 12:48:08 +0100
Subject: [PATCH 11/48] duplicate logic
---
application/controllers/Header_auth.php | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 8a67f63d4..9b1d7141c 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -187,27 +187,6 @@ class Header_auth extends CI_Controller {
];
$this->input->set_cookie($cookie);
- // Get full user record
- $user = $this->user_model->get($username)->row();
-
- // Critical: Update session data
- $this->user_model->update_session($user->user_id);
- $this->user_model->set_last_seen($user->user_id);
-
- // Set essential session data
- $this->session->set_userdata(array(
- 'user_id' => $user->user_id,
- 'user_name' => $user->user_name,
- 'user_type' => $user->user_type,
- 'user_stylesheet' => $user->user_stylesheet ?? 'bootstrap',
- 'user_column1' => $user->user_column1 ?? 'Mode',
- 'user_column2' => $user->user_column2 ?? 'RSTS',
- 'user_column3' => $user->user_column3 ?? 'RSTR',
- 'user_column4' => $user->user_column4 ?? 'Band',
- 'user_column5' => $user->user_column5 ?? 'Country',
- // Add other preferences as needed
- ));
-
log_message('info', "User ID [{$user->user_id}] logged in via header auth.");
redirect('dashboard');
}
From 670afc0f50c1e8c07be6c46c2e6fddb39f6cafc1 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 12:53:52 +0100
Subject: [PATCH 12/48] catch null
---
application/controllers/User.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/application/controllers/User.php b/application/controllers/User.php
index 7ee578fd2..44b6df6db 100644
--- a/application/controllers/User.php
+++ b/application/controllers/User.php
@@ -1224,8 +1224,8 @@ class User extends CI_Controller {
if ($this->form_validation->run() == FALSE) {
$data['page_title'] = __("Login");
$data['https_check'] = $this->https_check();
- $data['auth_header_enable'] = $this->config->item('auth_header_enable');
- $data['auth_header_text'] = $this->config->item('auth_header_text');
+ $data['auth_header_enable'] = $this->config->item('auth_header_enable') ?? false;
+ $data['auth_header_text'] = $this->config->item('auth_header_text') ?: '';
$this->load->view('interface_assets/mini_header', $data);
$this->load->view('user/login');
$this->load->view('interface_assets/footer');
From ce04003621bfcbf3140900285aa6ba7cfd3d0602 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 13:39:39 +0100
Subject: [PATCH 13/48] added missing user_config
---
application/controllers/Header_auth.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 9b1d7141c..702fdd310 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -137,6 +137,7 @@ class Header_auth extends CI_Controller {
"", // oqrs_auto_matching
"", // oqrs_direct_auto_matching
"", // user_dxwaterfall_enable
+ "", // user_qso_show_map
);
switch ($result) {
From ee5dd2425f4a2a35fd5b0ea697bc875304126639 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 18:32:17 +0100
Subject: [PATCH 14/48] jwt logic
---
application/controllers/Header_auth.php | 157 ++++++++++++++++++------
1 file changed, 118 insertions(+), 39 deletions(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 702fdd310..36d28bc01 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -9,76 +9,155 @@ class Header_auth extends CI_Controller {
public function __construct() {
parent::__construct();
- $this->load->model('user_model');
- $this->load->library('session');
- $this->load->helper('url');
}
- /**
- * Authenticate using a trusted request header.
- * Expected to be called from a login-screen button.
+ /**
+ * Decode a JWT token
+ *
+ * @param string $token
+ *
+ * @return array|null
+ */
+ private function _decode_jwt_payload(string $token): ?array {
+ $parts = explode('.', $token);
+ if (count($parts) !== 3) {
+ return null;
+ }
+
+ $decode = function(string $part): ?array {
+ $json = base64_decode(str_pad(strtr($part, '-_', '+/'), strlen($part) % 4, '=', STR_PAD_RIGHT));
+ if ($json === false) return null;
+ $data = json_decode($json, true);
+ return is_array($data) ? $data : null;
+ };
+
+ $header = $decode($parts[0]);
+ $payload = $decode($parts[1]);
+ if ($payload === null) {
+ return null;
+ }
+
+ // Merge alg from header into payload so _verify_jwtdata can check it
+ if (isset($header['alg'])) {
+ $payload['alg'] = $header['alg'];
+ }
+
+ return $payload;
+ }
+
+ /**
+ * Helper to verify some long hangig fruits. We are not verifying the JWT token against the issuer at this point.
+ * Reason is the need for a crypto lib which is not necessary at this point. An administrator is responsible
+ * for the proper isolation of Wavelog and needs to make sure that Wavelog is not exposed directly.
+ *
+ * Additonal verificarion steps can be added at a later point.
+ *
+ * @param array claim data
+ *
+ * @return bool
+ */
+ private function _verify_jwtdata($claims = null) {
+ // No claim, no verificiation
+ if (!$claims) {
+ log_message('error', 'JWT Verification: No claim data received.');
+ return false;
+ }
+
+ // Check expire date
+ if (($claims['exp'] ?? 0) < time()) {
+ log_message('error', 'JWT Verification: JWT Token is expired.');
+ return false;
+ }
+
+ // Is the token already valid
+ if (isset($claims['nbf']) && $claims['nbf'] > time()) {
+ log_message('error', 'JWT Verification: JWT Token is not valid yet.');
+ return false;
+ }
+
+ // The token should not be older then 24 hours which would be absurd old for an JWT token
+ if (isset($claims['iat']) && $claims['iat'] < (time() - 86400)) {
+ log_message('error', 'JWT Verification: Token is older then 24 hours. This is very unusual. Verification failed.');
+ return false;
+ }
+
+ // Is it a bearer token?
+ if (isset($claims['typ']) && $claims['typ'] !== 'Bearer') {
+ log_message('error', 'JWT Verification: JWT Token is no Bearer Token.');
+ return false;
+ }
+
+ // prevent alg: none attacks
+ if (!in_array($claims['alg'], ['RS256', 'RS384', 'RS512', 'ES256', 'ES384'], true)) {
+ log_message('error', 'JWT Verification: Algorithm ' . ($claims['alg'] ?? '???') . ' is not allowed. Create an issue on github https://github.com/wavelog/wavelog.');
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Authenticate using a trusted request header.
*/
public function login() {
- // Guard: feature must be enabled
+ // Guard: feature must be enabled
if (!$this->config->item('auth_header_enable')) {
$this->session->set_flashdata('error', __('Header authentication is disabled.'));
redirect('user/login');
}
-
- // Get username from header
- $headerUsername = $this->config->item('auth_headers_username') ?: '';
- if (empty($headerUsername)) {
- $this->session->set_flashdata('error', __('Missing header setting.'));
+ // Decode JWT access token forwarded by idp
+ $token = $this->input->server('HTTP_X_FORWARDED_ACCESS_TOKEN', true);
+ if (empty($token)) {
+ $this->session->set_flashdata('error', __('Missing access token header.'));
redirect('user/login');
}
- $username = $this->input->server($headerUsername, true);
+
+ $claims = $this->_decode_jwt_payload($token);
+ if (empty($claims)) {
+ $this->session->set_flashdata('error', __('Invalid access token.'));
+ redirect('user/login');
+ }
+
+ if (!$this->_verify_jwtdata($claims)) {
+ $this->session->set_flashdata('error', __('Token validation failed. For more information check out the error log.'));
+ redirect('user/login');
+ }
+
+ $username = $claims['preferred_username'] ?? '';
+ $email = $claims['email'] ?? '';
+ $callsign = $claims['callsign'] ?? '';
+ $firstname = $claims['given_name'] ?? '';
+ $lastname = $claims['family_name'] ?? '';
if (empty($username)) {
- $this->session->set_flashdata('error', __('Missing username header.'));
+ $this->session->set_flashdata('error', __('Missing username in access token.'));
redirect('user/login');
}
- // Look up user by the header value
+ // Look up user by the header value
+ $this->load->model('user_model');
$query = $this->user_model->get($username);
if (!$query || $query->num_rows() !== 1) {
// Config check if create user
if ($this->config->item('auth_header_create')) {
- $firstnameHeader = $this->config->item('auth_headers_firstname') ?: '';
- if (!empty($firstnameHeader)) {
- $firstname = $this->input->server($firstnameHeader, true);
- } else {
- $firstname = '';
- }
- $lastnameHeader = $this->config->item('auth_headers_lastname') ?: '';
- if (!empty($lastnameHeader)) {
- $lastname = $this->input->server($lastnameHeader, true);
- } else {
- $lastname = '';
- }
- $callsignHeader = $this->config->item('auth_headers_callsign') ?: '';
- if (!empty($callsignHeader)) {
- $callsign = $this->input->server($callsignHeader, true);
- } else {
- $this->session->set_flashdata('error', __('Missing callsign header.'));
+ if (empty($email)) {
+ $this->session->set_flashdata('error', __('Missing email in access token.'));
redirect('user/login');
}
- $emailHeader = $this->config->item('auth_headers_email') ?: '';
- if (!empty($emailHeader)) {
- $email = $this->input->server($emailHeader, true);
- } else {
- $this->session->set_flashdata('error', __('Missing email header.'));
+ if (empty($callsign)) {
+ $this->session->set_flashdata('error', __('Missing callsign in access token.'));
redirect('user/login');
}
- $club_id = $this->config->item('auth_header_club_id') ?: '';
+ // $club_id = $this->config->item('auth_header_club_id') ?: ''; // TODO: Add support to add a user to a clubstation
$result = $this->user_model->add(
$username,
bin2hex(random_bytes(64)), // password
$email,
- 3, // $data['user_type'], Anlage auf 3
+ 3, // $data['user_type'], we don't create admins for security reasons
$firstname,
$lastname,
$callsign,
From c049434f2afd69a42bad9530a09fcd10146f0d40 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 23:28:03 +0100
Subject: [PATCH 15/48] external_account flag for sso accounts
---
application/config/migration.php | 2 +-
application/controllers/Header_auth.php | 2 ++
application/controllers/User.php | 5 +++++
.../migrations/272_external_account.php | 21 +++++++++++++++++++
application/models/User_model.php | 3 ++-
5 files changed, 31 insertions(+), 2 deletions(-)
create mode 100644 application/migrations/272_external_account.php
diff --git a/application/config/migration.php b/application/config/migration.php
index dcd5de722..d6b180776 100644
--- a/application/config/migration.php
+++ b/application/config/migration.php
@@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE;
|
*/
-$config['migration_version'] = 271;
+$config['migration_version'] = 272;
/*
|--------------------------------------------------------------------------
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 36d28bc01..78b85a302 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -217,6 +217,8 @@ class Header_auth extends CI_Controller {
"", // oqrs_direct_auto_matching
"", // user_dxwaterfall_enable
"", // user_qso_show_map
+ 0, // clubstation
+ true, // external_account
);
switch ($result) {
diff --git a/application/controllers/User.php b/application/controllers/User.php
index 44b6df6db..49d6f4251 100644
--- a/application/controllers/User.php
+++ b/application/controllers/User.php
@@ -1300,6 +1300,11 @@ class User extends CI_Controller {
$this->input->set_cookie('tmp_msg', json_encode(['notice', sprintf(__("User %s logged out."), $user_name)]), 10, '');
}
+ $logout = $this->config->item('auth_url_logout');
+ if ($this->config->item('auth_header_enable') && $logout !== null && $logout !== '') {
+ redirect($logout);
+ }
+
redirect('user/login');
}
diff --git a/application/migrations/272_external_account.php b/application/migrations/272_external_account.php
new file mode 100644
index 000000000..bcb468d09
--- /dev/null
+++ b/application/migrations/272_external_account.php
@@ -0,0 +1,21 @@
+dbtry("ALTER TABLE users ADD COLUMN external_account tinyint DEFAULT 0 AFTER clubstation");
+ }
+
+ public function down() {
+ $this->dbtry("ALTER TABLE users DROP COLUMN external_account");
+ }
+
+ function dbtry($what) {
+ try {
+ $this->db->query($what);
+ } catch (Exception $e) {
+ log_message("error", "Something gone wrong while altering users table. Executing: " . $this->db->last_query());
+ }
+ }
+}
diff --git a/application/models/User_model.php b/application/models/User_model.php
index 3fc0e422b..c1102a6dc 100644
--- a/application/models/User_model.php
+++ b/application/models/User_model.php
@@ -225,7 +225,7 @@ class User_Model extends CI_Model {
$user_lotw_name, $user_lotw_password, $user_eqsl_name, $user_eqsl_password, $user_clublog_name, $user_clublog_password,
$user_winkey, $on_air_widget_enabled, $on_air_widget_display_last_seen, $on_air_widget_show_only_most_recent_radio,
$qso_widget_display_qso_time, $dashboard_banner, $dashboard_solar, $global_oqrs_text, $oqrs_grouped_search,
- $oqrs_grouped_search_show_station_name, $oqrs_auto_matching, $oqrs_direct_auto_matching,$user_dxwaterfall_enable, $user_qso_show_map, $clubstation = 0) {
+ $oqrs_grouped_search_show_station_name, $oqrs_auto_matching, $oqrs_direct_auto_matching,$user_dxwaterfall_enable, $user_qso_show_map, $clubstation = 0, $external_account = false) {
// Check that the user isn't already used
if(!$this->exists($username)) {
$data = array(
@@ -269,6 +269,7 @@ class User_Model extends CI_Model {
'user_clublog_password' => xss_clean($user_clublog_password),
'winkey' => xss_clean($user_winkey),
'clubstation' => $clubstation,
+ 'external_account' => $external_account
);
// Check the password is valid
From 4ed08b379c82e6831d316f0b21c7ed561b2123e1 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Sun, 8 Mar 2026 23:40:34 +0100
Subject: [PATCH 16/48] improve logging
---
application/controllers/Header_auth.php | 26 ++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/application/controllers/Header_auth.php b/application/controllers/Header_auth.php
index 78b85a302..a3722ce17 100644
--- a/application/controllers/Header_auth.php
+++ b/application/controllers/Header_auth.php
@@ -107,20 +107,29 @@ class Header_auth extends CI_Controller {
}
// Decode JWT access token forwarded by idp
- $token = $this->input->server('HTTP_X_FORWARDED_ACCESS_TOKEN', true);
+ $accesstoken_path = $this->config->item('auth_headers_accesstoken') ?? false;
+ if (!$accesstoken_path) {
+ log_message('error', 'SSO Authentication: Access Token Path not configured in config.php.');
+ $this->session->set_flashdata('error', __('SSO Config Error. Check error log.'));
+ redirect('user/login');
+ }
+ $token = $this->input->server($accesstoken_path, true);
if (empty($token)) {
- $this->session->set_flashdata('error', __('Missing access token header.'));
+ log_message('error', 'SSO Authentication: Missing access token header.');
+ $this->session->set_flashdata('error', __('SSO Config Error. Check error log.'));
redirect('user/login');
}
$claims = $this->_decode_jwt_payload($token);
if (empty($claims)) {
- $this->session->set_flashdata('error', __('Invalid access token.'));
+ log_message('error', 'SSO Authentication: Invalid access token format. Failed to decode JWT token.');
+ $this->session->set_flashdata('error', __('Config Error. Check error log.'));
redirect('user/login');
}
if (!$this->_verify_jwtdata($claims)) {
- $this->session->set_flashdata('error', __('Token validation failed. For more information check out the error log.'));
+ log_message('error', 'SSO Authentication: Token validation failed.');
+ $this->session->set_flashdata('error', __('Config Error. Check error log.'));
redirect('user/login');
}
@@ -131,7 +140,8 @@ class Header_auth extends CI_Controller {
$lastname = $claims['family_name'] ?? '';
if (empty($username)) {
- $this->session->set_flashdata('error', __('Missing username in access token.'));
+ log_message('error', 'SSO Authentication: Missing username claim in access token.');
+ $this->session->set_flashdata('error', __('Config Error. Check error log.'));
redirect('user/login');
}
@@ -143,11 +153,13 @@ class Header_auth extends CI_Controller {
// Config check if create user
if ($this->config->item('auth_header_create')) {
if (empty($email)) {
- $this->session->set_flashdata('error', __('Missing email in access token.'));
+ log_message('error', 'SSO Authentication: Missing email claim in access token.');
+ $this->session->set_flashdata('error', __('Config Error. Check error log.'));
redirect('user/login');
}
if (empty($callsign)) {
- $this->session->set_flashdata('error', __('Missing callsign in access token.'));
+ log_message('error', 'SSO Authentication: Missing callsign claim in access token.');
+ $this->session->set_flashdata('error', __('Config Error. Check error log.'));
redirect('user/login');
}
From 651845bf77de74bc0b25005ffe031e19d117ab20 Mon Sep 17 00:00:00 2001
From: HB9HIL
Date: Mon, 9 Mar 2026 12:02:37 +0100
Subject: [PATCH 17/48] add option to hide the normal login form
---
application/controllers/User.php | 1 +
application/models/User_model.php | 5 +++++
application/views/user/login.php | 20 +++++++++++---------
3 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/application/controllers/User.php b/application/controllers/User.php
index 49d6f4251..6da69968e 100644
--- a/application/controllers/User.php
+++ b/application/controllers/User.php
@@ -1226,6 +1226,7 @@ class User extends CI_Controller {
$data['https_check'] = $this->https_check();
$data['auth_header_enable'] = $this->config->item('auth_header_enable') ?? false;
$data['auth_header_text'] = $this->config->item('auth_header_text') ?: '';
+ $data['hide_login_form'] = ($data['auth_header_enable'] && !($this->config->item('auth_allow_direct_login') ?? true));
$this->load->view('interface_assets/mini_header', $data);
$this->load->view('user/login');
$this->load->view('interface_assets/footer');
diff --git a/application/models/User_model.php b/application/models/User_model.php
index c1102a6dc..2798b4c32 100644
--- a/application/models/User_model.php
+++ b/application/models/User_model.php
@@ -519,6 +519,11 @@ class User_Model extends CI_Model {
// This is really just a wrapper around User_Model::authenticate
function login() {
+ if (($this->config->item('auth_header_enable') ?? false) && !($this->config->item('auth_allow_direct_login') ?? true)) {
+ $this->session->set_flashdata('error', 'Direct login is disabled. Please use the SSO option to log in.');
+ redirect('user/login');
+ }
+
$username = $this->input->post('user_name', true);
$password = htmlspecialchars_decode($this->input->post('user_password', true));
diff --git a/application/views/user/login.php b/application/views/user/login.php
index 102e6ff7b..ddfbd9125 100644
--- a/application/views/user/login.php
+++ b/application/views/user/login.php
@@ -64,6 +64,7 @@
?>