Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • Experimental/newSaml2
  • Fix/xxxx-migrateLogin
  • Hotfix/1234-handlingMergeToken
  • Hotfix/1354-workingFHLogin
  • Hotfix/1357-ymlFile
  • Hotfix/1370-swaggerDescription
  • Hotfix/1545-emptyUserGraphs
  • Hotfix/2087-efNet6
  • Hotfix/2103-RepositoryurlstoConsulUpdateMappingGivennameDev
  • Hotfix/2103-RepositoryurlstoConsulUpdateMappingGivennameUiv2
  • Hotfix/2169-ignoreAuthContext
  • Hotfix/2576-certificatePatch
  • Hotfix/2592-sameProvider
  • Hotfix/2775-dfnCertRollover
  • Hotfix/64-releaseUDE
  • Issue/1833-newLogin
  • Issue/1910-MigrationtoNET6.0
  • Issue/1964-tokenExpiryUIv2
  • Issue/1974-shibbolethLogout
  • Issue/2078-renamingEntitlementAcceptStaff
  • Issue/2078-renamingEntitlementAcceptStaffUiv2
  • Issue/2115-extendParsingPairwiseId
  • Issue/2147-exchangingCoscineCertificate
  • Issue/2147-exchangingCoscineCertificate-step2
  • Issue/2147-exchangingCoscineCertificate-step3
  • Issue/2309-docs
  • Issue/2325-fixApiTokenMerging
  • Issue/3003-stsInstitute
  • Issue/40-rdsQuotaForUKA
  • Product/1149-dfnaai
  • Product/1287-dotnet5Sharepoint
  • Product/1290-dfnaai
  • Product/1414-fhPrivileges
  • Product/1629-onboardingOtherUniversities
  • Product/797-overhaul
  • Product/917-maintenanceFunctionality
  • Sprint/2020-20
  • Sprint/2020-21
  • Sprint/2020-22
  • Sprint/2021-01
  • Sprint/2021-03
  • Sprint/2021-05
  • Sprint/2021-06
  • Sprint/2021-08
  • Sprint/2021-10
  • Sprint/2021-11
  • Sprint/2021-19
  • Sprint/2021-20
  • Sprint/2021-23
  • Sprint/2022-01
  • Topic/1224-overhaul
  • Topic/1276-DFN-AAIFrontend
  • Topic/1278-dfnAAI
  • Topic/1297-maintenanceBanner
  • Topic/1335-dotnet5Apis
  • Topic/1425-fhPrivileges
  • Topic/1711-extendResourceTypeConfiguration
  • dev
  • gitkeep
  • master
  • top
  • uiv2
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.11.0
  • v1.11.1
  • v1.11.2
  • v1.11.3
  • v1.12.0
  • v1.13.0
  • v1.14.0
  • v1.14.1
  • v1.15.0
  • v1.16.0
  • v1.16.1
  • v1.16.2
  • v1.17.0
  • v1.18.0
  • v1.2.0
  • v1.2.1
  • v1.3.0
  • v1.4.0
  • v1.5.0
  • v1.6.0
  • v1.7.0
  • v1.8.0
  • v1.8.1
  • v1.9.0
  • v1.9.1
  • v2.0.0
  • v2.0.1
  • v2.0.2
  • v2.0.3
  • v2.1.0
  • v2.2.0
  • v2.2.1
  • v2.2.2
  • v2.2.3
  • v2.2.4
  • v2.3.0
  • v2.3.1
  • v2.3.2
  • v2.3.3
  • v2.4.0
  • v2.4.1
  • v2.4.2
  • v2.4.3
  • v2.4.4
  • v3.0.0
  • v3.1.0
  • v3.1.1
  • v3.1.2
  • v3.1.3
  • v3.1.4
  • v4.0.0
  • v4.0.1
  • v4.0.2
  • v4.0.3
  • v4.0.4
  • v4.0.5
  • v4.0.6
  • v4.0.7
  • v4.0.8
  • v4.0.9
  • v4.1.0
  • v4.1.1
129 results

Target

Select target project
  • coscine/backend/apis/sts
1 result
Select Git revision
  • Experimental/newSaml2
  • Fix/xxxx-migrateLogin
  • Hotfix/1234-handlingMergeToken
  • Hotfix/1354-workingFHLogin
  • Hotfix/1357-ymlFile
  • Hotfix/1370-swaggerDescription
  • Hotfix/1545-emptyUserGraphs
  • Hotfix/2087-efNet6
  • Hotfix/2103-RepositoryurlstoConsulUpdateMappingGivennameDev
  • Hotfix/2103-RepositoryurlstoConsulUpdateMappingGivennameUiv2
  • Hotfix/2169-ignoreAuthContext
  • Hotfix/2576-certificatePatch
  • Hotfix/2592-sameProvider
  • Hotfix/2775-dfnCertRollover
  • Hotfix/64-releaseUDE
  • Issue/1833-newLogin
  • Issue/1910-MigrationtoNET6.0
  • Issue/1964-tokenExpiryUIv2
  • Issue/1974-shibbolethLogout
  • Issue/2078-renamingEntitlementAcceptStaff
  • Issue/2078-renamingEntitlementAcceptStaffUiv2
  • Issue/2115-extendParsingPairwiseId
  • Issue/2147-exchangingCoscineCertificate
  • Issue/2147-exchangingCoscineCertificate-step2
  • Issue/2147-exchangingCoscineCertificate-step3
  • Issue/2309-docs
  • Issue/2325-fixApiTokenMerging
  • Issue/3003-stsInstitute
  • Issue/40-rdsQuotaForUKA
  • Product/1149-dfnaai
  • Product/1287-dotnet5Sharepoint
  • Product/1290-dfnaai
  • Product/1414-fhPrivileges
  • Product/1629-onboardingOtherUniversities
  • Product/797-overhaul
  • Product/917-maintenanceFunctionality
  • Sprint/2020-20
  • Sprint/2020-21
  • Sprint/2020-22
  • Sprint/2021-01
  • Sprint/2021-03
  • Sprint/2021-05
  • Sprint/2021-06
  • Sprint/2021-08
  • Sprint/2021-10
  • Sprint/2021-11
  • Sprint/2021-19
  • Sprint/2021-20
  • Sprint/2021-23
  • Sprint/2022-01
  • Topic/1224-overhaul
  • Topic/1276-DFN-AAIFrontend
  • Topic/1278-dfnAAI
  • Topic/1297-maintenanceBanner
  • Topic/1335-dotnet5Apis
  • Topic/1425-fhPrivileges
  • Topic/1711-extendResourceTypeConfiguration
  • dev
  • gitkeep
  • master
  • top
  • uiv2
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.11.0
  • v1.11.1
  • v1.11.2
  • v1.11.3
  • v1.12.0
  • v1.13.0
  • v1.14.0
  • v1.14.1
  • v1.15.0
  • v1.16.0
  • v1.16.1
  • v1.16.2
  • v1.17.0
  • v1.18.0
  • v1.2.0
  • v1.2.1
  • v1.3.0
  • v1.4.0
  • v1.5.0
  • v1.6.0
  • v1.7.0
  • v1.8.0
  • v1.8.1
  • v1.9.0
  • v1.9.1
  • v2.0.0
  • v2.0.1
  • v2.0.2
  • v2.0.3
  • v2.1.0
  • v2.2.0
  • v2.2.1
  • v2.2.2
  • v2.2.3
  • v2.2.4
  • v2.3.0
  • v2.3.1
  • v2.3.2
  • v2.3.3
  • v2.4.0
  • v2.4.1
  • v2.4.2
  • v2.4.3
  • v2.4.4
  • v3.0.0
  • v3.1.0
  • v3.1.1
  • v3.1.2
  • v3.1.3
  • v3.1.4
  • v4.0.0
  • v4.0.1
  • v4.0.2
  • v4.0.3
  • v4.0.4
  • v4.0.5
  • v4.0.6
  • v4.0.7
  • v4.0.8
  • v4.0.9
  • v4.1.0
  • v4.1.1
129 results
Show changes
Commits on Source (3)
......@@ -40,14 +40,6 @@ namespace Coscine.Api.STS.Controllers
{
await _signInManager.SignOutAsync();
foreach (var cookie in Request.Cookies.Keys)
{
if (cookie != MergeController.MERGETOKENKEY)
{
Response.Cookies.Delete(cookie);
}
}
ViewBag.LoginUrl = UrlGenerator.GetLoginUrl(Request) + "?logout=true";
return Redirect(ViewBag.LoginUrl);
......
......@@ -28,12 +28,6 @@ namespace Coscine.Api.STS.Controllers
var userIdString = User.Identity.Name;
var userId = new Guid(userIdString);
if (Request.Cookies.ContainsKey(MergeController.MERGETOKENKEY))
{
string mergeCallbackUrl = UrlGenerator.MergeCallbackRedirectUrl();
return Redirect(mergeCallbackUrl);
}
ProcessSignIn(User);
// Process where the user will be redirected to
......
using Coscine.Api.STS.Data;
using Coscine.Api.STS.Utils;
using Coscine.Database.Models;
using Coscine.JwtHandler;
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 = ORCiDHandler.GetORCiDOAuthUrl() + 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();
var validMerge = false;
var userModel = new UserModel();
var userIdString = User.Identity.Name;
var userId = new Guid(userIdString);
var mergeFromUser = userModel.GetById(userId);
var externalAuthenticatorModel = new ExternalAuthenticatorModel();
var externalIdModel = new ExternalIdModel();
// Check if logged in user has a possible login from the defined LoginMethod
if (contents != null && contents.Any((claim) => claim.Type == "LoginMethod"))
{
var loginMethodClaim = contents.Where((claim) => claim.Type == "LoginMethod").First();
switch (loginMethodClaim.Value)
{
case "orcid":
var orcidAuthItem = externalAuthenticatorModel.GetWhere((externalAuthenticator) => externalAuthenticator.DisplayName == "ORCiD");
var orcidMapping = externalIdModel.GetAllWhere((map) => map.UserId == userId && map.ExternalAuthenticatorId == orcidAuthItem.Id);
validMerge = orcidMapping.Count() > 0;
break;
case "shibboleth":
var shibbolethAuthItem = externalAuthenticatorModel.GetWhere((externalAuthenticator) => externalAuthenticator.DisplayName == "Shibboleth");
var shibbolethMapping = externalIdModel.GetAllWhere((map) => map.UserId == userId && map.ExternalAuthenticatorId == shibbolethAuthItem.Id);
validMerge = shibbolethMapping.Count() > 0;
break;
default:
break;
}
}
if (validMerge && contents?.Any((claim) => claim.Type == "UserGuid") == true)
{
var userGuidString = contents.First((claim) => claim.Type == "UserGuid");
var correctGuid = Guid.TryParse(userGuidString.Value, out Guid userGuid);
if (correctGuid)
{
var userList = userModel.GetAllWhere((user) => user.Id == userGuid);
if (userList.Any())
{
var mergeIntoUser = userList.First();
if (mergeFromUser.Id != mergeIntoUser.Id)
{
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));
}
}
}
}
else if (contents?.Any((claim) => claim.Type == "UserGuid") == true)
{
var userGuidString = contents.First((claim) => claim.Type == "UserGuid");
var coscineUser = new CoscineUser()
{
UserName = userGuidString.Value,
Email = ""
};
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];
var handler = new JWTHandler(Program.Configuration);
if (handler.TryValidateToken(mergeToken))
{
return handler.GetContents(mergeToken);
}
}
return null;
}
private void DeleteCookie()
{
if (Request.Cookies.ContainsKey(MERGETOKENKEY))
{
Response.Cookies.Delete(MERGETOKENKEY);
}
}
}
}
......@@ -6,7 +6,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TargetFramework>net6.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Version>4.1.0</Version>
<Version>4.1.1</Version>
</PropertyGroup>
<PropertyGroup>
<Authors>RWTH Aachen University</Authors>
......@@ -21,6 +21,7 @@
<PackageReference Include="Coscine.Action" Version="3.*-*" />
<PackageReference Include="Coscine.ActiveDirectory" Version="2.*-*" />
<PackageReference Include="Coscine.ApiCommons" Version="2.*-*" />
<PackageReference Include="Coscine.Database" Version="2.22.0" />
<PackageReference Include="Coscine.JwtHandler" Version="2.*-*" />
<PackageReference Include="Coscine.Metadata" Version="2.*-*" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.4" />
......
using Coscine.Action;
using Coscine.Action.EventArgs;
using Coscine.ActiveDirectory;
using Coscine.Configuration;
using Coscine.Database.DataModel;
using Coscine.Database.Models;
using Coscine.Database.Util;
using LinqKit;
using System.Linq;
namespace Coscine.Api.STS.Utils
{
public class MergeUtil
{
private readonly ExternalIdModel _externalIdModel;
private readonly ProjectModel _projectModel;
private readonly ProjectRoleModel _projectRoleModel;
private readonly ResourceModel _resourceModel;
private readonly RoleModel _roleModel;
private readonly TOSModel _tosModel;
private readonly ApiTokenModel _apiTokenModel;
private readonly UserModel _userModel;
private readonly UserDisciplineModel _userDisciplineModel;
private readonly Emitter _emitter;
public MergeUtil() : this(Program.Configuration)
{
}
public MergeUtil(IConfiguration configuration)
{
_externalIdModel = new ExternalIdModel();
_projectModel = new ProjectModel();
_projectRoleModel = new ProjectRoleModel();
_resourceModel = new ResourceModel();
_roleModel = new RoleModel();
_tosModel = new TOSModel();
_apiTokenModel = new ApiTokenModel();
_userModel = new UserModel();
_userDisciplineModel = new UserDisciplineModel();
_emitter = new Emitter(configuration);
}
public void MergeFromUserIntoUser(User mergeFromUser, User mergeIntoUser)
{
MergeProjectRole(mergeIntoUser, mergeFromUser);
MergeUserDiscipline(mergeIntoUser, mergeFromUser);
MergeResourceOwner(mergeIntoUser, mergeFromUser);
MergeTOSAccepted(mergeIntoUser, mergeFromUser);
MergeApiTokens(mergeIntoUser, mergeFromUser);
MergeUserProperties(mergeIntoUser, mergeFromUser);
// ExternalId gets merged last, in case something goes wrong
MergeExternalId(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))
{
var project = _projectModel.GetById(projectRole.ProjectId);
var role = _roleModel.GetById(projectRole.RoleId);
// Check if entry already exists
if (_projectRoleModel.GetAllWhere(
(entry) =>
entry.UserId == mergeIntoUser.Id
&& entry.ProjectId == projectRole.ProjectId
).Count() == 0)
{
_emitter.EmitUserRemove(new UserEventArgs(Program.Configuration)
{
Project = project,
Role = role,
User = mergeFromUser,
SilentMode = true
});
projectRole.UserId = mergeIntoUser.Id;
_projectRoleModel.Update(projectRole);
_emitter.EmitUserAdd(new UserEventArgs(Program.Configuration)
{
Project = project,
Role = role,
User = mergeIntoUser,
SilentMode = true
});
}
else
{
_projectRoleModel.Delete(projectRole);
_emitter.EmitUserRemove(new UserEventArgs(Program.Configuration)
{
Project = project,
Role = role,
User = mergeFromUser,
SilentMode = true
});
}
}
}
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)
{
// Get every resource, also get the deleted ones
foreach (
var resource in DatabaseConnection.ConnectToDatabase((db) =>
{
return
(from tableEntry in db.Resources.AsExpandable()
where tableEntry.Creator == mergeFromUser.Id
select tableEntry).ToList();
})
)
{
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 MergeApiTokens(User mergeIntoUser, User mergeFromUser)
{
foreach (var apiToken in _apiTokenModel.GetAllWhere((entry) => entry.UserId == mergeFromUser.Id))
{
apiToken.UserId = mergeIntoUser.Id;
_apiTokenModel.Update(apiToken);
}
}
private void MergeUserProperties(User mergeIntoUser, User mergeFromUser)
{
if (string.IsNullOrEmpty(mergeIntoUser.EmailAddress) && !string.IsNullOrEmpty(mergeFromUser.EmailAddress))
{
mergeIntoUser.EmailAddress = mergeFromUser.EmailAddress;
}
if (string.IsNullOrEmpty(mergeIntoUser.Surname) && !string.IsNullOrEmpty(mergeFromUser.Surname))
{
mergeIntoUser.Surname = mergeIntoUser.Surname;
}
if (string.IsNullOrEmpty(mergeIntoUser.Givenname) && !string.IsNullOrEmpty(mergeFromUser.Givenname))
{
mergeIntoUser.Givenname = mergeIntoUser.Givenname;
}
if (mergeIntoUser.TitleId == null && mergeFromUser.TitleId != null)
{
mergeIntoUser.TitleId = mergeFromUser.TitleId;
}
if (string.IsNullOrEmpty(mergeIntoUser.Organization) && !string.IsNullOrEmpty(mergeFromUser.Organization))
{
mergeIntoUser.Organization = mergeFromUser.Organization;
}
if (string.IsNullOrEmpty(mergeIntoUser.Institute) && !string.IsNullOrEmpty(mergeFromUser.Institute))
{
mergeIntoUser.Institute = mergeFromUser.Institute;
}
_userModel.Update(mergeIntoUser);
}
private void DeleteUser(User user)
{
_userModel.Delete(user);
ADHandler.DeleteUser(user, Program.Configuration);
}
}
}