Skip to content

Commit

Permalink
Add support for MS Corporate URIs - fixes #134, fixes #143, fixes #147
Browse files Browse the repository at this point in the history
  • Loading branch information
Bubka committed Jul 6, 2023
1 parent 244a7ad commit 48bdf69
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 deletions.
25 changes: 22 additions & 3 deletions app/Models/TwoFAccount.php
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,28 @@ public function fillWithURI(string $uri, bool $isSteamTotp = false, bool $skipIc
try {
$this->generator = Factory::loadFromProvisioningUri($isSteamTotp ? str_replace('otpauth://steam', 'otpauth://totp', $uri) : $uri);
} catch (\Exception|\Throwable $ex) {
throw ValidationException::withMessages([
'uri' => __('validation.custom.uri.regex', ['attribute' => 'uri']),
]);

// Hack for Microsoft corporate 2FAs for whom the Issuer query parameter != the Issuer aside the account
$parsed_uri = \OTPHP\Url::fromString($uri);
$pathChunks = explode(':', rawurldecode(mb_substr($parsed_uri->getPath(), 1)));
$service = $pathChunks[0];
$issuer = data_get($parsed_uri->getQuery(), 'issuer', $service);

if (count($pathChunks) == 2 && strtolower($issuer) == 'microsoft' && strcasecmp($issuer, $service) != 0) {
$newUri = str_replace($pathChunks[0] . ':', '', rawurldecode($uri));
try {
$this->generator = Factory::loadFromProvisioningUri($newUri);
$this->generator->setLabel($service . '_' . $this->generator->getLabel());
} catch (\Exception|\Throwable $ex) {
throw ValidationException::withMessages([
'uri' => __('validation.custom.uri.regex', ['attribute' => 'uri']),
]);
}
} else {
throw ValidationException::withMessages([
'uri' => __('validation.custom.uri.regex', ['attribute' => 'uri']),
]);
}
}

// As loadFromProvisioningUri() accept URI without label (nor account nor service) we check
Expand Down
8 changes: 8 additions & 0 deletions tests/Data/OtpTestData.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ class OtpTestData

const TOTP_FULL_CUSTOM_URI_NO_IMG = 'otpauth://totp/' . self::SERVICE . ':' . self::ACCOUNT . '?secret=' . self::SECRET . '&issuer=' . self::SERVICE . '&digits=' . self::DIGITS_CUSTOM . '&period=' . self::PERIOD_CUSTOM . '&algorithm=' . self::ALGORITHM_CUSTOM;

const MICROSOFT = 'Microsoft';

const ORGANIZATION = 'MyOrganization';

const TOTP_MICROSOFT_CORPORATE_URI_MISMATCHING_ISSUER = 'otpauth://totp/' . self::ORGANIZATION . ':' . self::ACCOUNT . '?secret=' . self::SECRET . '&issuer=' . self::MICROSOFT;

const TOTP_FULL_CUSTOM_URI = self::TOTP_FULL_CUSTOM_URI_NO_IMG . '&image=' . self::IMAGE;

const HOTP_FULL_CUSTOM_URI_NO_IMG = 'otpauth://hotp/' . self::SERVICE . ':' . self::ACCOUNT . '?secret=' . self::SECRET . '&issuer=' . self::SERVICE . '&digits=' . self::DIGITS_CUSTOM . '&counter=' . self::COUNTER_CUSTOM . '&algorithm=' . self::ALGORITHM_CUSTOM;
Expand All @@ -72,6 +78,8 @@ class OtpTestData

const INVALID_OTPAUTH_URI = 'otpauth://Xotp/' . self::ACCOUNT . '?secret=' . self::SECRET;

const INVALID_OTPAUTH_URI_MISMATCHING_ISSUER = 'otpauth://totp/' . self::MICROSOFT . ':' . self::ACCOUNT . '?secret=' . self::SECRET . '&issuer=' . self::SERVICE;

const STEAM_TOTP_URI = 'otpauth://totp/' . self::STEAM . ':' . self::ACCOUNT . '?secret=' . self::STEAM_SECRET . '&issuer=' . self::STEAM . '&digits=' . self::DIGITS_STEAM . '&period=30&algorithm=' . self::ALGORITHM_DEFAULT;

const ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP = [
Expand Down
29 changes: 29 additions & 0 deletions tests/Feature/Models/TwoFAccountModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,25 @@ public function test_fill_with_basic_totp_uri_returns_default_value()
$this->assertEquals(null, $twofaccount->icon);
}

/**
* @test
*/
public function test_fill_with_ms_corporate_totp_uri_returns_correct_value()
{
$twofaccount = new TwoFAccount;
$twofaccount->fillWithURI(OtpTestData::TOTP_MICROSOFT_CORPORATE_URI_MISMATCHING_ISSUER);

$this->assertEquals('totp', $twofaccount->otp_type);
$this->assertEquals(OtpTestData::TOTP_MICROSOFT_CORPORATE_URI_MISMATCHING_ISSUER, $twofaccount->legacy_uri);
$this->assertEquals(OtpTestData::MICROSOFT, $twofaccount->service);
$this->assertEquals(OtpTestData::ORGANIZATION . '_' . OtpTestData::ACCOUNT, $twofaccount->account);
$this->assertEquals(OtpTestData::SECRET, $twofaccount->secret);
$this->assertEquals(OtpTestData::DIGITS_DEFAULT, $twofaccount->digits);
$this->assertEquals(OtpTestData::PERIOD_DEFAULT, $twofaccount->period);
$this->assertEquals(null, $twofaccount->counter);
$this->assertEquals(OtpTestData::ALGORITHM_DEFAULT, $twofaccount->algorithm);
}

/**
* @test
*/
Expand Down Expand Up @@ -228,6 +247,16 @@ public function test_fill_with_invalid_uri_returns_ValidationException()
$twofaccount->fillWithURI(OtpTestData::INVALID_OTPAUTH_URI);
}

/**
* @test
*/
public function test_fill_with_invalid_uri_with_mismatching_issuer_returns_ValidationException()
{
$this->expectException(\Illuminate\Validation\ValidationException::class);
$twofaccount = new TwoFAccount;
$twofaccount->fillWithURI(OtpTestData::INVALID_OTPAUTH_URI_MISMATCHING_ISSUER);
}

/**
* @test
*/
Expand Down

0 comments on commit 48bdf69

Please sign in to comment.