Skip to content
Snippets Groups Projects
Commit e1bf5a45 authored by Marcel Nellesen's avatar Marcel Nellesen
Browse files

Merge branch 'Sprint/2020-11' into 'master'

Sprint/2020 11

See merge request coscine/api/sts!51
parents 1cd9f4b2 35bc5285
Branches
Tags v1.13.0
1 merge request!51Sprint/2020 11
......@@ -63,7 +63,10 @@ namespace Coscine.Api.STS.Controllers
foreach (var cookie in Request.Cookies.Keys)
{
Response.Cookies.Delete(cookie);
if (cookie != MergeController.MERGETOKENKEY)
{
Response.Cookies.Delete(cookie);
}
}
ViewBag.LoginUrl = UrlGenerator.GetLoginUrl(Request) + "&logout=true";
......
......@@ -36,12 +36,13 @@ namespace Coscine.Api.STS.Controllers
var userIdString = User.Identity.Name;
var userId = new Guid(userIdString);
TOSModel tosModel = new TOSModel();
var tosAcceptedList = tosModel.GetAllWhere((entry) => entry.UserId == userId);
var currentTos = Configurator.Configuration.GetStringAndWait("coscine/global/tos/version");
var tosAccepted = tosAcceptedList != null
&& tosAcceptedList.Any((entry) => entry.Version == currentTos);
if (!tosAccepted)
if (Request.Cookies.ContainsKey(MergeController.MERGETOKENKEY))
{
string mergeCallbackUrl = UrlGenerator.MergeCallbackRedirectUrl();
return Redirect(mergeCallbackUrl);
}
if (!AreTOSAccepted(userId))
{
string tosUrl = UrlGenerator.GetTOSUrl(Request, userIdString);
return Redirect(tosUrl);
......@@ -58,6 +59,15 @@ namespace Coscine.Api.STS.Controllers
return Redirect(loginUrl);
}
private bool AreTOSAccepted(Guid userId)
{
TOSModel tosModel = new TOSModel();
var tosAcceptedList = tosModel.GetAllWhere((entry) => entry.UserId == userId);
var currentTos = Configurator.Configuration.GetStringAndWait("coscine/global/tos/version");
return tosAcceptedList != null
&& tosAcceptedList.Any((entry) => entry.Version == currentTos);
}
private string ProcessSignIn(Uri url, ClaimsPrincipal user)
{
var requestMessage = (SignInRequestMessage)WSFederationMessage.CreateFromUri(url);
......
using Coscine.Api.STS.Data;
using Coscine.Api.STS.Utils;
using Coscine.ApiCommons.Utils;
using Coscine.Database.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Coscine.Api.STS.Controllers
{
public class MergeController : Controller
{
public const string MERGETOKENKEY = "coscine.mergetoken";
private readonly SignInManager<CoscineUser> _signInManager;
public MergeController(SignInManager<CoscineUser> signInManager)
{
_signInManager = signInManager;
}
[Route("[controller]/login")]
public ActionResult Login(string returnUrl = null)
{
var contents = GetContents();
if (contents != null && contents.Any((claim) => claim.Type == "LoginMethod"))
{
var loginMethodClaim = contents.Where((claim) => claim.Type == "LoginMethod").First();
switch (loginMethodClaim.Value)
{
case "orcid":
string orcidUrl = UrlGenerator.ORCiDRedirectUrl();
return Redirect(orcidUrl);
case "shibboleth":
string shibbolethUrl = UrlGenerator.ShibbolethRedirectUrl();
return Redirect(shibbolethUrl);
default:
break;
}
}
// If something is wrong with the token or method, just redirect back to login page and invalidate the token
DeleteCookie();
string loginUrl = UrlGenerator.GetLoginUrl(Request);
return Redirect(loginUrl);
}
[Route("[controller]/callback")]
public async Task<ActionResult> Callback(string returnUrl = null)
{
var contents = GetContents();
DeleteCookie();
if (contents != null && contents.Any((claim) => claim.Type == "UserGuid"))
{
var userGuidString = contents.Where((claim) => claim.Type == "UserGuid").First();
var correctGuid = Guid.TryParse(userGuidString.Value, out Guid userGuid);
if (correctGuid)
{
var userModel = new UserModel();
var userList = userModel.GetAllWhere((user) => user.Id == userGuid);
if (userList.Count() > 0)
{
var mergeIntoUser = userList.First();
var userIdString = User.Identity.Name;
var userId = new Guid(userIdString);
var mergeFromUser = userModel.GetById(userId);
var mergeUtil = new MergeUtil();
mergeUtil.MergeFromUserIntoUser(mergeFromUser, mergeIntoUser);
// Logout the old account and login the user into his merged account after merging has finished
await _signInManager.SignOutAsync();
var coscineUser = new CoscineUser()
{
UserName = mergeIntoUser.Id.ToString(),
Email = mergeIntoUser.EmailAddress ?? ""
};
var result = await _signInManager.UserManager.CreateAsync(coscineUser);
await _signInManager.SignInAsync(coscineUser, isPersistent: false);
return Redirect(UrlGenerator.ExtendReturnUrl(returnUrl, Request));
}
}
}
string loginUrl = UrlGenerator.GetLoginUrl(Request);
return Redirect(loginUrl);
}
private IEnumerable<Claim> GetContents()
{
if (Request.Cookies.ContainsKey(MERGETOKENKEY))
{
var mergeToken = Request.Cookies[MERGETOKENKEY];
JWTHandler handler = new JWTHandler(Program.Configuration);
if (handler.ValidToken(mergeToken))
{
return handler.GetContents(mergeToken);
}
}
return null;
}
private void DeleteCookie()
{
if (Request.Cookies.ContainsKey(MERGETOKENKEY))
{
Response.Cookies.Delete(MERGETOKENKEY);
}
}
}
}
......@@ -11,7 +11,6 @@ using System.Threading.Tasks;
namespace Coscine.Api.STS.Controllers
{
[Route("[controller]/[action]")]
public class ShibbolethController : Controller
{
private readonly SignInManager<CoscineUser> _signInManager;
......@@ -21,7 +20,7 @@ namespace Coscine.Api.STS.Controllers
_signInManager = signInManager;
}
[HttpGet]
[Route("[controller]/callback")]
public async Task<ActionResult> Callback(string returnUrl = null, string remoteError = null)
{
if (remoteError != null)
......@@ -76,7 +75,7 @@ namespace Coscine.Api.STS.Controllers
return Redirect(UrlGenerator.ExtendReturnUrl(returnUrl, Request));
}
[HttpPost]
[Route("[controller]/login")]
public ActionResult Login(string returnUrl)
{
var provider = "Saml2";
......
......@@ -9,9 +9,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Coscine.ActiveDirectory" Version="1.1.0" />
<PackageReference Include="Coscine.ActiveDirectory" Version="1.2.0-topic-861-mergea0001" />
<PackageReference Include="Coscine.ApiCommons" Version="1.8.0" />
<PackageReference Include="Coscine.Database" Version="1.21.0" />
<PackageReference Include="Coscine.Database" Version="1.22.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Abstractions" Version="2.2.0" />
......
using Coscine.ActiveDirectory;
using Coscine.Database.DataModel;
using Coscine.Database.Models;
using LinqToDB.Tools;
using System.Linq;
namespace Coscine.Api.STS.Utils
{
public class MergeUtil
{
private readonly ExternalIdModel _externalIdModel;
private readonly ProjectRoleModel _projectRoleModel;
private readonly ResourceModel _resourceModel;
private readonly TOSModel _tosModel;
private readonly UserModel _userModel;
private readonly UserDisciplineModel _userDisciplineModel;
public MergeUtil()
{
_externalIdModel = new ExternalIdModel();
_projectRoleModel = new ProjectRoleModel();
_resourceModel = new ResourceModel();
_tosModel = new TOSModel();
_userModel = new UserModel();
_userDisciplineModel = new UserDisciplineModel();
}
public void MergeFromUserIntoUser(User mergeFromUser, User mergeIntoUser)
{
MergeExternalId(mergeIntoUser, mergeFromUser);
MergeProjectRole(mergeIntoUser, mergeFromUser);
MergeUserDiscipline(mergeIntoUser, mergeFromUser);
MergeResourceOwner(mergeIntoUser, mergeFromUser);
MergeTOSAccepted(mergeIntoUser, mergeFromUser);
DeleteUser(mergeFromUser);
}
private void MergeExternalId(User mergeIntoUser, User mergeFromUser)
{
foreach (var externalId in _externalIdModel.GetAllWhere((entry) => entry.UserId == mergeFromUser.Id))
{
// Check if entry already exists
if (_externalIdModel.GetAllWhere(
(entry) =>
entry.UserId == mergeIntoUser.Id
&& entry.ExternalAuthenticatorId == externalId.ExternalAuthenticatorId
).Count() == 0)
{
externalId.UserId = mergeIntoUser.Id;
_externalIdModel.Update(externalId);
}
else
{
_externalIdModel.Delete(externalId);
}
}
}
private void MergeProjectRole(User mergeIntoUser, User mergeFromUser)
{
foreach (var projectRole in _projectRoleModel.GetAllWhere((entry) => entry.UserId == mergeFromUser.Id))
{
// Check if entry already exists
if (_projectRoleModel.GetAllWhere(
(entry) =>
entry.UserId == mergeIntoUser.Id
&& entry.ProjectId == projectRole.ProjectId
).Count() == 0)
{
projectRole.UserId = mergeIntoUser.Id;
_projectRoleModel.Update(projectRole);
}
else
{
_projectRoleModel.Delete(projectRole);
}
}
}
private void MergeUserDiscipline(User mergeIntoUser, User mergeFromUser)
{
foreach (var userDiscipline in _userDisciplineModel.GetAllWhere((entry) => entry.UserId == mergeFromUser.Id))
{
// Check if entry already exists
if (_userDisciplineModel.GetAllWhere(
(entry) =>
entry.UserId == mergeIntoUser.Id
&& entry.DisciplineId == userDiscipline.DisciplineId
).Count() == 0)
{
userDiscipline.UserId = mergeIntoUser.Id;
_userDisciplineModel.Update(userDiscipline);
}
else
{
_userDisciplineModel.Delete(userDiscipline);
}
}
}
private void MergeResourceOwner(User mergeIntoUser, User mergeFromUser)
{
foreach(var resource in _resourceModel.GetAllWhere((entry) => entry.Creator == mergeFromUser.Id))
{
resource.Creator = mergeIntoUser.Id;
_resourceModel.Update(resource);
}
}
private void MergeTOSAccepted(User mergeIntoUser, User mergeFromUser)
{
foreach (var tosAccepted in _tosModel.GetAllWhere((entry) => entry.UserId == mergeFromUser.Id))
{
// Check if entry already exists
if (_tosModel.GetAllWhere(
(entry) =>
entry.UserId == mergeIntoUser.Id
&& entry.Version == tosAccepted.Version
).Count() == 0)
{
tosAccepted.UserId = mergeIntoUser.Id;
_tosModel.Update(tosAccepted);
}
else
{
_tosModel.Delete(tosAccepted);
}
}
}
private void DeleteUser(User user)
{
_userModel.Delete(user);
ADHandler.DeleteUser(user, Program.Configuration);
}
}
}
......@@ -75,5 +75,15 @@ namespace Coscine.Api.STS.Utils
{
return Program.MainUrl + "/orcid/login?ReturnUrl=" + Program.MainUrl;
}
public static string ShibbolethRedirectUrl()
{
return Program.MainUrl + "/shibboleth/login?ReturnUrl=" + Program.MainUrl;
}
public static string MergeCallbackRedirectUrl()
{
return Program.MainUrl + "/merge/callback?ReturnUrl=" + Program.MainUrl;
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment