Skip to content
Snippets Groups Projects
Select Git revision
  • ea877b5c064b1b41013679a05ad6fa2ef8142e38
  • master default protected
  • dev protected
  • Issue/3003-stsInstitute
  • gitkeep
  • Hotfix/2775-dfnCertRollover
  • Hotfix/2592-sameProvider
  • Hotfix/1234-handlingMergeToken
  • Hotfix/2576-certificatePatch
  • Issue/2309-docs
  • Issue/2325-fixApiTokenMerging
  • Issue/1974-shibbolethLogout
  • Fix/xxxx-migrateLogin
  • Hotfix/2169-ignoreAuthContext
  • Experimental/newSaml2
  • Issue/2147-exchangingCoscineCertificate-step2
  • Issue/2147-exchangingCoscineCertificate
  • Issue/2147-exchangingCoscineCertificate-step3
  • uiv2
  • Issue/2115-extendParsingPairwiseId
  • Hotfix/2103-RepositoryurlstoConsulUpdateMappingGivennameUiv2
  • v4.1.1
  • v4.1.0
  • v4.0.9
  • v4.0.8
  • v4.0.7
  • v4.0.6
  • v4.0.5
  • v4.0.4
  • v4.0.3
  • v4.0.2
  • v4.0.1
  • v4.0.0
  • v3.1.4
  • v3.1.3
  • v3.1.2
  • v3.1.1
  • v3.1.0
  • v3.0.0
  • v2.4.4
  • v2.4.3
41 results

ShibbolethController.cs

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ShibbolethController.cs 5.98 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"));
            }
    
            [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 = entity[(entity.IndexOf(">") + 1)..];
                identifier = identifier.Substring(0, identifier.IndexOf("<"));
    
                var entityId = entity[(entity.IndexOf("NameQualifier=\"") + "NameQualifier=\"".Length)..];
                entityId = entityId.Substring(0, entityId.IndexOf("\""));
    
                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 == "Entitlement").Key);
                    if (eduPersonScopedAffiliation.Any(x => x.Value.StartsWith("employee@"))
                        // Check for test shib (employee user is actually member...).
                        || (eduPersonScopedAffiliation.Any(x => x.Value.StartsWith("member@") && entityId == "https://login-test.rz.rwth-aachen.de/shibboleth")))
                    {
                        // Add membership information.
                        _rdfStoreConnector.AddMemebershipData(userGraphName, organization);
                    }
                }
    
                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"></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);
            }
        }
    }