Select Git revision
ResourceStructuralData.cs
-
Hanna Führ authoredHanna Führ authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ShibbolethController.cs 6.68 KiB
using Coscine.Api.STS.Data;
using Coscine.Api.STS.Utils;
using Coscine.Database.DataModel;
using Coscine.Database.Models;
using Coscine.Metadata;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Coscine.Api.STS.Controllers
{
public class ShibbolethController : Controller
{
private readonly SignInManager<CoscineUser> _signInManager;
private readonly RdfStoreConnector _rdfStoreConnector;
public ShibbolethController(SignInManager<CoscineUser> signInManager)
{
_signInManager = signInManager;
_rdfStoreConnector = new RdfStoreConnector(Program.Configuration.GetString("coscine/local/virtuoso/additional/url"));
}
/// <summary>
/// Callback method to catch the login
/// </summary>
/// <param name="returnUrl">URL to be redirected to</param>
/// <param name="remoteError">Erros on remote login</param>
/// <returns>Redirect</returns>
/// <exception cref="ArgumentException"></exception>
[Route("[controller]/callback")]
public async Task<ActionResult> Callback(string returnUrl = null, string remoteError = null)
{
if (remoteError != null)
{
throw new ArgumentException($"Error from external provider: {remoteError}");
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return Redirect(UrlGenerator.GetLoginUrl(Request));
}
var externalAuthenticatorModel = new ExternalAuthenticatorModel();
var shibbolethAuthItem = externalAuthenticatorModel.GetWhere((externalAuthenticator) => externalAuthenticator.DisplayName == "Shibboleth");
var externalIdModel = new ExternalIdModel();
var entity = info.Principal.FindFirstValue(ShibbolethAttributeMapping.Identifier);
if (string.IsNullOrWhiteSpace(entity))
{
entity = info.Principal.FindFirstValue(ShibbolethAttributeMapping.PairwiseID);
}
var identifier = "";
var entityId = "";
if (entity.IndexOf(">") > -1)
{
identifier = entity[(entity.IndexOf(">") + 1)..];
identifier = identifier.Substring(0, identifier.IndexOf("<"));
entityId = entity[(entity.IndexOf("NameQualifier=\"") + "NameQualifier=\"".Length)..];
entityId = entityId.Substring(0, entityId.IndexOf("\""));
}
else
{
identifier = entity;
entityId = info.AuthenticationProperties.Items["idp"];
}
var mapping = externalIdModel.GetAllWhere((map) =>
map.ExternalId1 == identifier
&& map.ExternalAuthenticatorId == shibbolethAuthItem.Id
&& map.Organization == entityId
);
User user;
var userModel = new UserModel();
if (mapping.Any())
{
var userId = mapping.First().UserId;
user = userModel.GetById(userId);
}
else
{
user = ShibbolethAttributeMapping.CreateUser(info.Principal);
userModel.Insert(user);
externalIdModel.Insert(new ExternalId
{
ExternalId1 = identifier,
ExternalAuthenticatorId = shibbolethAuthItem.Id,
Organization = entityId,
UserId = user.Id
});
}
var userGraphName = $"{_rdfStoreConnector.UserUrlPrefix}/{user.Id}";
// Make sure the user graph exists.
_rdfStoreConnector.EnsureGraph(userGraphName);
// Get organization.
var organization = _rdfStoreConnector.GetOrganization(entityId, identifier);
// Can only update data if an org was found.
if (organization != null)
{
// Drop old membership infromation.
_rdfStoreConnector.RemoveMembershipData(userGraphName, organization);
// Reverse lookup...
var eduPersonScopedAffiliation = info.Principal.FindAll(ShibbolethAttributeMapping.LabelMapping.FirstOrDefault(x => x.Value == "ScopedAffiliation").Key);
var orgFromId = _rdfStoreConnector.GetOrgnizationWithIdentifier(identifier);
if (eduPersonScopedAffiliation.Any(x => x.Value.StartsWith("employee@") || x.Value.StartsWith("staff@")))
{
// Add membership information.
_rdfStoreConnector.AddMemebershipData(userGraphName, organization);
}
else if (orgFromId != null)
{
// Add membership information.
_rdfStoreConnector.AddMemebershipData(userGraphName, orgFromId);
}
}
var coscineUser = new CoscineUser()
{
UserName = user.Id.ToString(),
Email = user.EmailAddress ?? ""
};
var result = await _signInManager.UserManager.CreateAsync(coscineUser);
result = await _signInManager.UserManager.AddLoginAsync(coscineUser, info);
await _signInManager.SignInAsync(coscineUser, isPersistent: false);
return Redirect(UrlGenerator.ExtendReturnUrl(returnUrl, Request));
}
/// <summary>
/// This method is the central route for logging into an identity provider.
/// On default, the user is redirected to the WAFY of the DFN-AAI.
/// Setting the "entityId" parameter allows the application to redirect to a specific identity provider defined by DFN-AAI.
/// </summary>
/// <param name="returnUrl">URL to be redirected to</param>
/// <param name="entityId">Specific Identitiy Provider to be redirect to</param>
/// <returns>ChallengeResult</returns>
[Route("[controller]/login")]
public ActionResult Login(string returnUrl = "/", string entityId = null)
{
var provider = "Saml2";
var redirectUrl = Program.MainUrl + "/Shibboleth/callback?returnUrl=" + returnUrl;
redirectUrl = UrlGenerator.ExtendReturnUrl(redirectUrl, Request);
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
if (entityId != null)
{
properties.Items.Add("idp", entityId);
}
return new ChallengeResult(provider, properties);
}
}
}