我正在构建一个连接到基于 Shibboleth 的 SAML IdP 的 .net 4.5 MVC 应用程序,以提供单点登录功能。为此,我使用了 Kentor.AuthServices.Owin 中间件。
有问题的 IdP 服务需要使用加密断言,而最新版本的 Kentor.AuthServices 不支持。相反,我不得不在这里使用它的 Raschmann-fork https://github.com/Raschmann/authservices/tree/78EncryptedAssertion (v0.8.1),然后尝试 ..Raschmann/authservices/tree/Release (v0.10.1)。
(使用 ..Raschmann/authservices/tree/master (v0.12.1) - 或者实际上任何 KentorIT Kentor.AuthServices 构建 - 导致 loginInfo 在 ExternalLoginCallback 中为空。)
使用上述内容,我可以通过 IdP 在应用程序上登录/注册。但是,当调用 ExternalLoginCallback 时,loginInfo.ExternalIdentity 中的 ExternalClaims 或 Claims 对象不包含任何声明。
我已捕获并解密来自 IdP 的 SAML 响应,并确认在我登录后它正在将信息(例如名字、姓氏、DoB 等)发送回我的应用程序。
如何访问正在返回的 SAML 数据?
在 Startup.Auth.vb 中配置身份验证:
Public Sub ConfigureAuth(app As IAppBuilder)
' Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(AddressOf ApplicationDbContext.Create)
app.CreatePerOwinContext(Of ApplicationUserManager)(AddressOf ApplicationUserManager.Create)
app.CreatePerOwinContext(Of ApplicationSignInManager)(AddressOf ApplicationSignInManager.Create)
app.UseCookieAuthentication(New CookieAuthenticationOptions() With {
.AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
.Provider = New CookieAuthenticationProvider() With {
.OnValidateIdentity = SecurityStampValidator.OnValidateIdentity(Of ApplicationUserManager, ApplicationUser)(
validateInterval:=TimeSpan.FromMinutes(30),
regenerateIdentity:=Function(manager, user) user.GenerateUserIdentityAsync(manager))},
.LoginPath = New PathString("/Account/Login")})
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie)
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5))
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie)
app.UseKentorAuthServicesAuthentication(New KentorAuthServicesAuthenticationOptions(True))
AntiForgeryConfig.UniqueClaimTypeIdentifier = Global.System.IdentityModel.Claims.ClaimTypes.NameIdentifier
End Sub
AccountController.vb 中的 ExternalLoginCallback:
<AllowAnonymous>
Public Async Function ExternalLoginCallback(returnUrl As String) As Task(Of ActionResult)
Dim loginInfo = Await AuthenticationManager.GetExternalLoginInfoAsync()
If loginInfo Is Nothing Then
Return RedirectToAction("Login")
End If
Dim externalIdentity = Await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie)
' Sign in the user with this external login provider if the user already has a login
Dim result = Await SignInManager.ExternalSignInAsync(loginInfo, isPersistent:=False)
Select Case result
Case SignInStatus.Success
Dim user = Await UserManager.FindAsync(loginInfo.Login)
If user IsNot Nothing Then
'user.FirstName = loginInfo.ExternalIdentity.FindFirst(ClaimTypes.Name).Value
'user.Email = loginInfo.ExternalIdentity.FindFirst(ClaimTypes.Email).Value
Await UserManager.UpdateAsync(user)
End If
Return RedirectToLocal(returnUrl)
Case SignInStatus.LockedOut
Return View("Lockout")
Case SignInStatus.RequiresVerification
Return RedirectToAction("SendCode", New With {
.ReturnUrl = returnUrl,
.RememberMe = False
})
Case Else
' If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl
ViewBag.LoginProvider = loginInfo.Login.LoginProvider
Return View("ExternalLoginConfirmation", New ExternalLoginConfirmationViewModel() With {
.Email = loginInfo.Email
})
End Select
End Function