Skip to content

Commit

Permalink
RavenDB-19951 Introduce TOTP support for browser generated requests
Browse files Browse the repository at this point in the history
  • Loading branch information
ml054 committed Dec 11, 2023
1 parent d44c386 commit e58b426
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ private void GetAllRegisteredCertificates(
}
}

[RavenAction("/certificates/whoami", "GET", AuthorizationStatus.ValidUser, EndpointType.Read)]
[RavenAction("/certificates/whoami", "GET", AuthorizationStatus.UnauthenticatedClients)]
public async Task WhoAmI()
{
var clientCert = GetCurrentCertificate();
Expand Down
11 changes: 11 additions & 0 deletions src/Raven.Server/Web/System/StudioHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,17 @@ public Task GetTwoFactorIndexFile()
HttpContext.Response.StatusCode = (int)HttpStatusCode.Moved;
return Task.CompletedTask;
}

[RavenAction("/2fa/$", "GET", AuthorizationStatus.UnauthenticatedClients)]
public Task GetTwoFactorFile()
{
var serverRelativeFileName = RouteMatch.Url.Substring(
RouteMatch.MatchLength,
RouteMatch.Url.Length - RouteMatch.MatchLength
);

return GetStudioFileInternal(serverRelativeFileName);
}

[RavenAction("/wizard/index.html", "GET", AuthorizationStatus.UnauthenticatedClients)]
public Task GetSetupIndexFile()
Expand Down
40 changes: 37 additions & 3 deletions src/Raven.Studio/typescript/viewmodels/twoFactorShell.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,74 @@
import viewModelBase from "viewmodels/viewModelBase";
import validateTwoFactorSecretCommand from "commands/auth/validateTwoFactorSecretCommand";
import getTwoFactorServerConfigurationCommand from "commands/auth/getTwoFactorServerConfigurationCommand";
import requestExecution from "common/notifications/requestExecution";
import protractedCommandsDetector from "common/notifications/protractedCommandsDetector";
import getClientCertificateCommand from "commands/auth/getClientCertificateCommand";

type LimitType = "browser" | "noLimit";

class twoFactorShell extends viewModelBase {
view = require("views/twoFactorShell.html");

studioLoadingFakeRequest: requestExecution;

certificateName = ko.observable<string>();

focusProceed = ko.observable<boolean>(false);

sessionDurationInMin = ko.observable<number>();
maxSessionDurationInMin = ko.observable<number>();

code = ko.observable<string>();
withLimits = ko.observable<boolean>(false);
limitType = ko.observable<LimitType>("browser");

constructor() {
super();

this.studioLoadingFakeRequest = protractedCommandsDetector.instance.requestStarted(0);

this.code.subscribe(c => {
if (c?.length === 6) {
this.focusProceed(true);
}
})

this.bindToCurrentInstance("verify");
}

activate(args: any) {
super.activate(args);

const clientCertificateTask = new getClientCertificateCommand()
.execute()
.done(clientCert => {
this.certificateName(clientCert.Name);
});

return new getTwoFactorServerConfigurationCommand()
const twoFactorConfigTask = new getTwoFactorServerConfigurationCommand()
.execute()
.done(response => {
this.sessionDurationInMin(response.DefaultTwoFactorSessionDurationInMin);
this.maxSessionDurationInMin(response.MaxTwoFactorSessionDurationInMin);
});

return $.when<any>(clientCertificateTask, twoFactorConfigTask);
}

compositionComplete() {
super.compositionComplete();
$("body").removeClass('loading-active');

this.studioLoadingFakeRequest.markCompleted();
this.studioLoadingFakeRequest = null;
}

verify() {
if (!this.code() || this.code().length !== 6) {
return;
}

new validateTwoFactorSecretCommand(this.code(), this.withLimits(), this.sessionDurationInMin())
new validateTwoFactorSecretCommand(this.code(), this.limitType() === "browser", this.sessionDurationInMin())
.execute()
.done(() => {
location.href = location.origin;
Expand Down
11 changes: 4 additions & 7 deletions src/Raven.Studio/wwwroot/App/views/twoFactorShell.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ <h3 class="text-lighter m-0">2FA Authentication</h3>
<i class="icon-unlock"></i>
</div>
<div>
<p class="m-0">Certificate name: <strong>{certificateName}</strong></p>
<p class="m-0">Certificate name: <strong data-bind="text: certificateName"></strong></p>
<p class="m-0">Enter the 6-digit authentication code generated by your app</p>
</div>
<form data-bind="submit: verify" class="tfa-form">
Expand Down Expand Up @@ -83,24 +83,21 @@ <h5 class="panel-title">
<div>
<div class="d-flex flex-wrap justify-content-between">
<label>Access clearance</label>
<small class="text-info" class="access-clearance-popover">
<i class="icon-info"></i> What's this?
</small>
</div>
<div class="d-flex flex-wrap gap-2">
<div class="radio radio-default radio-inline">
<input id="browserTrust" type="radio" data-bind="checked: withLimits">
<input id="browserTrust" type="radio" data-bind="checked: limitType" value="browser">
<label for="browserTrust" class="margin-left-xs mb-0"><small>Trust only this browser</small></label>
</div>
<div class="radio radio-default radio-inline">
<input id="allTrust" type="radio" data-bind="checked: !withLimits">
<input id="allTrust" type="radio" data-bind="checked: limitType" value="noLimit">
<label for="allTrust" class="margin-left-xs mb-0"><small>Trust all with this certificate</small></label>
</div>
</div>
</div>
</div>
</div>
</div>
<button class="btn btn-primary rounded-pill"><i class="icon-arrow-thin-right"></i> Proceed</button>
<button class="btn btn-primary rounded-pill" data-bind="hasFocus: focusProceed"><i class="icon-arrow-thin-right"></i> Proceed</button>
</form>
</div>
2 changes: 1 addition & 1 deletion src/Raven.Studio/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
var link = document.createElement("link");
link.rel = "stylesheet";
link.id = "raven-theme";
link.href = "../studio/styles/" + themeToCss[themeToUse];
link.href = "styles/" + themeToCss[themeToUse];

var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
Expand Down

0 comments on commit e58b426

Please sign in to comment.