Skip to content

Instantly share code, notes, and snippets.

@ilmax
Created October 1, 2015 12:12
Show Gist options
  • Save ilmax/71fc46d7fc35ef2f8fc8 to your computer and use it in GitHub Desktop.
Save ilmax/71fc46d7fc35ef2f8fc8 to your computer and use it in GitHub Desktop.
[Authorize, HttpPost, Route("~/connect/authorize/accept"), ValidateAntiForgeryToken]
public async Task<ActionResult> Accept(CancellationToken cancellationToken)
{
// Extract the authorization request from the cache, the query string or the request form.
var request = OwinContext.GetOpenIdConnectRequest();
if (request == null)
{
return View("Error", new OpenIdConnectMessage
{
Error = "invalid_request",
ErrorDescription = "An internal error has occurred"
});
}
// Create a new ClaimsIdentity containing the claims that
// will be used to create an id_token, a token or a code.
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationType);
foreach (var claim in OwinContext.Authentication.User.Claims)
{
// Allow ClaimTypes.Name to be added in the id_token.
// ClaimTypes.NameIdentifier is automatically added, even if its
// destination is not defined or doesn't include "id_token".
// The other claims won't be visible for the client application.
if (claim.Type == ClaimTypes.Name)
{
claim.WithDestination("id_token")
.WithDestination("token");
}
identity.AddClaim(claim);
}
// Note: Owin.Security.OpenIdConnect.Server automatically ensures an application
// corresponds to the client_id specified in the authorization request using
// IOpenIdConnectServerProvider.ValidateClientRedirectUri (see AuthorizationProvider.cs).
// In theory, this null check is thus not strictly necessary. That said, a race condition
// and a null reference exception could appear here if you manually removed the application
// details from the database after the initial check made by Owin.Security.OpenIdConnect.Server.
var application = await GetApplicationAsync(request.ClientId, CancellationToken.None);
if (application == null)
{
return View("Error", new OpenIdConnectMessage
{
Error = "invalid_client",
ErrorDescription = "Details concerning the calling client application cannot be found in the database"
});
}
// Create a new ClaimsIdentity containing the claims associated with the application.
// Note: setting identity.Actor is not mandatory but can be useful to access
// the whole delegation chain from the resource server (see ResourceController.cs).
identity.Actor = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationType);
identity.Actor.AddClaim(ClaimTypes.NameIdentifier, application.ApplicationID);
identity.Actor.AddClaim(ClaimTypes.Name, application.DisplayName, destination: "id_token token");
// This call will instruct Owin.Security.OpenIdConnect.Server to serialize
// the specified identity to build appropriate tokens (id_token and token).
// Note: you should always make sure the identities you return contain either
// a 'sub' or a 'ClaimTypes.NameIdentifier' claim. In this case, the returned
// identities always contain the name identifier returned by the external provider.
OwinContext.Authentication.SignIn(identity);
return new HttpStatusCodeResult(200);
}
[Authorize, HttpPost, Route("~/connect/authorize/deny"), ValidateAntiForgeryToken]
public ActionResult Deny(CancellationToken cancellationToken)
{
// Extract the authorization request from the cache, the query string or the request form.
var request = OwinContext.GetOpenIdConnectRequest();
if (request == null)
{
return View("Error", new OpenIdConnectMessage
{
Error = "invalid_request",
ErrorDescription = "An internal error has occurred"
});
}
// Notify Owin.Security.OpenIdConnect.Server that the authorization grant has been denied.
// Note: OpenIdConnectServerHandler will automatically take care of redirecting
// the user agent to the client application using the appropriate response_mode.
OwinContext.SetOpenIdConnectResponse(new OpenIdConnectMessage
{
Error = "access_denied",
ErrorDescription = "The authorization grant has been denied by the resource owner",
RedirectUri = request.RedirectUri,
State = request.State
});
return new HttpStatusCodeResult(200);
}
[HttpPost, Route("~/connect/authorize/login"), ValidateAntiForgeryToken]
public async Task<ActionResult> PasswordLogin(CancellationToken cancellationToken, LoginModel login)
{
Debug.Assert(!User.Identity.IsAuthenticated);
// Extract the authorization request from the cache, the query string or the request form.
var request = OwinContext.GetOpenIdConnectRequest();
if (request == null)
{
return View("Error", new OpenIdConnectMessage
{
Error = "invalid_request",
ErrorDescription = "An internal error has occurred"
});
}
// Note: Owin.Security.OpenIdConnect.Server automatically ensures an application
// corresponds to the client_id specified in the authorization request using
// IOpenIdConnectServerProvider.ValidateClientRedirectUri (see AuthorizationProvider.cs).
// In theory, this null check is thus not strictly necessary. That said, a race condition
// and a null reference exception could appear here if you manually removed the application
// details from the database after the initial check made by Owin.Security.OpenIdConnect.Server.
var application = await GetApplicationAsync(request.ClientId, cancellationToken);
if (application == null)
{
return View("Error", new OpenIdConnectMessage
{
Error = "invalid_client",
ErrorDescription = "Details concerning the calling client application cannot be found in the database"
});
}
// Implement your credential validation logic and create an identity with all necessary claims
// NOTE! you MUST add at least the "sub" or ClaimTypes.NameIdentifier claim to the created identity
if (login.UserName == login.Password)
{
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, login.UserName).WithDestination("id_token token"));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "1").WithDestination("id_token token"));
if (application.RequireUserConsent)
{
// Note this is because we generate an AntiForgeryToken in both Views (Authorize & Login) so we should consume (remove)
// the token used by Login view.
request.Parameters.Remove("__RequestVerificationToken");
// Note: in a real world application, you'd probably prefer creating a specific view model.
return View("Authorize", Tuple.Create(request, application));
}
// Where should i put this line ?
OwinContext.Authentication.SignIn(identity);
return new HttpStatusCodeResult(200);
}
return View("Login", new LoginViewModel(login.Unique_Id, "Wrong password"));
}
@using Microsoft.IdentityModel.Protocols
@using Mvc.Server.Models
@using Owin.Security.OpenIdConnect.Extensions
@model Tuple<OpenIdConnectMessage, Application>
<div class="jumbotron">
<h1>Authorization</h1>
<p class="lead text-left">Do you wanna grant <strong>@Model.Item2.DisplayName</strong> an access to your resources? (scopes requested: @Model.Item1.Scope)</p>
<p class="lead text-left"><strong>@Model.Item2.DisplayName</strong> will be able to access the following endpoints: @string.Join(" ; ", Model.Item1.GetResources())</p>
<form enctype="application/x-www-form-urlencoded" method="post">
@Html.AntiForgeryToken()
@foreach (var parameter in Model.Item1.Parameters) {
<input type="hidden" name="@parameter.Key" value="@parameter.Value" />
}
<input formaction="/connect/authorize/accept" class="btn btn-lg btn-success" name="Authorize" type="submit" value="Yeah, sure" />
<input formaction="/connect/authorize/deny" class="btn btn-lg btn-danger" name="Deny" type="submit" value="Hell, no" />
</form>
</div>
@model Mvc.Server.Models.LoginViewModel
@{
ViewBag.Title = "Login";
}
<div class="jumbotron">
<h2>Login</h2>
<h1>Authorization Server</h1>
@if (!string.IsNullOrEmpty(Model.Error))
{
<h1 style="color:red">@Model.Error</h1>
}
<form action="/connect/authorize/login" enctype="application/x-www-form-urlencoded" method="post">
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Forms Login</h4>
<hr />
<input type="hidden" name="unique_id" value="@Model.UniqueId" />
<div class="form-group">
<div class="col-md-10">
<label for="UserName">User name: </label>
<input type="text" id="UserName" name="username" />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<label for="Password">Password: </label>
<input type="password" id="Password" name="password" />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<label for="RememberMe">Remember Me</label>
<input type="checkbox" id="RememberMe" name="isPersistent" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Sign In" class="btn btn-default" />
</div>
</div>
</div>
</form>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment