外部クレームのためのSTSトークンの有効期間(a azure ACS)
-
10-12-2019 - |
質問
私は、Formsベース認証(FBA)を使用してSharePoint 2013を使用している既存のシステムを変更して、アカウントのアカウントの自己サービスと管理を自己サービスの作成できます。管理できるものの1つは役割のメンバーシップです。事実上、それらはシステムに供給する役割アクセスコードを与えられ、それらをロールに追加し、それらが役割が与えられたサイトにアクセスすることを可能にする。ソリューションの一部は、これをサポートし、それをよりユーザーフレンドリーにするのに役立つカスタムログイン画面です。これはすべて比較的よく機能しています。
フォームベースの認証ではなく外部認証プロバイダのサポートを追加するタスクです - これはビジネス要件です。たくさんのオンライン情報があります(例: http://blogs.msn.com/b/mvpawardprogram/archive / mvps-for-sharePoint-2010- azure-acs-v2 to-azure-extronce-systems-users.aspx を使用すると、Azure ACSをIDプロバイダとして追加しています。この問題は、セルフサービスロール認証ピースを追加する方法です。
私は http://www.microsoft.com/en-us/download/details.aspx?id=27569 。私が打つ問題は、トークンでキャッシングしているインボックスSTSの「一般的な」号であるため、ユーザーの役割のメンバーシップが変更されたとき、それらは依然として古いキャッシュされたトークンを取得します。私の主張増強コードは呼ばれていません(もちろんSTSがキャッシュされたチケットを使用しているときのようななぜそれはなぜそれはなぜなのでしょう)、メンバーシップの変化は見られません。
これは http://www.shillier.com/archive/2010/10/25/authorization-Failures-Sclaims-authentication-in-SharePoint-authentication-in-SharePoint-2010.aspx 与えられたトークンの有効期間を変更すること。私はこれに関する問題と質問がいくつかあります。
-
外部クレームシナリオでは、一生の適用は何ですか? Windowsトークンではなく、FBAトークンではないので、
WindowsTokenLifetime
もFormsTokenLifetime
も適切ではありません。 -
私は、トークンが不当な短時間でエンドユーザーの期限切れに失効したくない、私はSTSがキャッシュされたバージョンを期限切れにしたいです。 - 私は気にしません、私たちの規模では関係ありません。ただし、これら2つのことが結合されているようです。それらを切り離す方法はありますか?
-
切り離すことができない場合は、ログイン画面が私が請求を再調整したいシステムに指示する方法はありますか?現在のユーザーアイデンティティを変更することで、自分自身にできることはできますか?それはシステムの後ろに続くのはもちろん、私がそれを助けることができるならば、私はそれをしたくありません。
-
これは、他のすべての可動部品が正しいように見えるので、これ以上OOB STSのキャッシングに最終的に降りるようです。これを回避する「正しい」方法は、キャッシング動作を持たず、それをIDプロバイダとして登録するカスタムSTSを作成することを避けることですか? (私がその時点でクレームの増強に悩まないように思われる場合、私はその時点での主張の増大に気にしないようです。私は知っていますが http://archive.msn.microsoft.com/selfsts )などのサンプルがあります。それは私がAzure ACSへの頼りパーティー接続をazure ACSに接続しなければならないようですので、OOB STSは、いくつかの労働力といくつかの努力で「魔法のように」します。
-
または、私はクレームを放棄し、単にFBA側を変更する必要がありますか?それは今後、私はFBAの認証コードですべてのOpenIDものを接続する必要があります。
FBAモデルでは、ユーザーが再度サインインすることで直ちに変更を行うことができます。
解決
OK、私はこの働きを手に入れました(yay!)、しかし男、それは難しかったです。
基本的には、トークンをSTSから再発行するように強制する必要があります。これにより、クレーム拡張コードが再び実行されます。私の訴訟では、実際には特許請求の範囲の1つだけが可能であるが、それがこの質問の即時の範囲外にあるため、ビジネス要件はもう少し複雑でした。
本質的に、私は https://stackoverflow.com/questions/8070456/RE --Calculate - Claims-for-SharePoint-2010-user-while-the-user-is-still-logged -in / 8185646#8185646 。私がしなければならなかったことの1つは、それが完全に認証を完全に破壊したので、e.ReissueCookie
を削除しました(ユーザーはその措置によってログアウトされました)。私の場合、私は特別なページを通してそれをしたくなかったので、私はそれに行動した後にすぐに消去したアプリケーションコレクションでユーザー固有の値を使いました。 global.asax
でコードを追加して削除するマイイベント受信機の関連コードは次のとおりです。
private readonly string AsaxText = @"
<%@ Assembly Name=""" + System.Reflection.Assembly.GetAssembly(typeof(ClaimSupport)).FullName + @"""%>
<script runat='server'>
void SessionAuthentication_SessionSecurityTokenReceived(object sender, Microsoft.IdentityModel.Web.SessionSecurityTokenReceivedEventArgs e) {
var application = HttpContext.Current.Application;
if (application == null) {
return;
}
var key = Company.SharePoint.Authentication.Data.ClaimSupport.ApplicationEventKey(e.SessionToken.ClaimsPrincipal.Identity.Name);
var applicationValue = application[key];
if (applicationValue == null) {
return;
}
var applicationString = applicationValue.ToString();
if (string.IsNullOrWhiteSpace(applicationString)) {
return;
}
application[key] = null;
var sam = sender as Microsoft.IdentityModel.Web.SessionAuthenticationModule;
var logonWindow = Microsoft.SharePoint.Administration.Claims.SPSecurityTokenServiceManager.Local.LogonTokenCacheExpirationWindow;
var newValidTo = System.DateTime.UtcNow.Add(logonWindow);
var currentPrincipal = e.SessionToken.ClaimsPrincipal;
var claimsIdentity = (Microsoft.IdentityModel.Claims.IClaimsIdentity)currentPrincipal.Identity;
var heartbeatClaim = GetHeartbeatClaim(claimsIdentity);
var issuer = heartbeatClaim.Issuer;
var originalIssuer = heartbeatClaim.OriginalIssuer;
RemoveExistingEventClaims(claimsIdentity);
AddEventClaim(claimsIdentity, applicationString, issuer, originalIssuer);
e.SessionToken = sam.CreateSessionSecurityToken(
currentPrincipal,
e.SessionToken.Context,
e.SessionToken.ValidFrom,
newValidTo,
e.SessionToken.IsPersistent);
//e.ReissueCookie = true; - commented out because it broke things for me, but kept for reference
}
private Microsoft.IdentityModel.Claims.Claim GetHeartbeatClaim(Microsoft.IdentityModel.Claims.IClaimsIdentity claimsIdentity) {
var heartbeatClaim = (from c in claimsIdentity.Claims
where
(c.ClaimType == Company.SharePoint.Authentication.Data.ClaimSupport.EventClaimType)
&&
(c.Value == Company.SharePoint.Authentication.Data.ClaimSupport.HeartbeatClaimValue)
select c).FirstOrDefault();
return heartbeatClaim;
}
private void AddEventClaim(Microsoft.IdentityModel.Claims.IClaimsIdentity claimsIdentity, string additionalEvent, string issuer, string originalIssuer) {
var eventClaim = new Microsoft.IdentityModel.Claims.Claim(Company.SharePoint.Authentication.Data.ClaimSupport.EventClaimType, additionalEvent, HynesITe.SharePoint.Authentication.Data.ClaimSupport.EventClaimValueType, issuer, originalIssuer);
claimsIdentity.Claims.Add(eventClaim);
}
private static void RemoveExistingEventClaims(Microsoft.IdentityModel.Claims.IClaimsIdentity claimsIdentity) {
var currentClaims = (from c in claimsIdentity.Claims
where
(c.ClaimType == HynesITe.SharePoint.Authentication.Data.ClaimSupport.EventClaimType)
&&
(c.Value != HynesITe.SharePoint.Authentication.Data.ClaimSupport.HeartbeatClaimValue)
select c).ToList();
foreach (var claim in currentClaims) {
claimsIdentity.Claims.Remove(claim);
}
}
</script>
";
private void AddGlobalAsax(SPFeatureReceiverProperties properties) {
var webApp = properties.Feature.Parent as SPWebApplication;
if (webApp == null) {
throw new SPException("Cannot add global.asax entries.");
}
var zones = Enum.GetValues(typeof(SPUrlZone)).Cast<SPUrlZone>().ToArray();
var paths =
zones.Select(z => Path.Combine(webApp.GetIisSettingsWithFallback(z).Path.ToString(), "global.asax"))
.Distinct().Where(File.Exists).ToArray();
var globalAsaxFiles = new List<string>();
globalAsaxFiles.AddRange(paths);
foreach (var asax in from asax in globalAsaxFiles
let contents = File.ReadAllText(asax)
where !contents.Contains(AsaxText)
select asax) {
File.AppendAllText(asax, AsaxText);
}
}
private void RemoveGlobalAsax(SPFeatureReceiverProperties properties) {
var webApp = properties.Feature.Parent as SPWebApplication;
if (webApp == null) {
throw new SPException("Cannot add global.asax entries.");
}
var zones = Enum.GetValues(typeof(SPUrlZone)).Cast<SPUrlZone>().ToArray();
var paths =
zones.Select(z => Path.Combine(webApp.GetIisSettingsWithFallback(z).Path.ToString(), "global.asax"))
.Distinct().Where(File.Exists).ToArray();
var globalAsaxFiles = new List<string>();
globalAsaxFiles.AddRange(paths);
foreach (var asax in globalAsaxFiles) {
var contents = File.ReadAllText(asax);
if (contents.Contains(AsaxText)) {
var replaced = contents.Replace(AsaxText, string.Empty);
File.WriteAllText(asax, replaced);
}
}
}
public override void FeatureActivated(SPFeatureReceiverProperties properties) {
// other stuff
AddGlobalAsax(properties);
// other stuff
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {
// other stuff
RemoveGlobalAsax(properties);
// other stuff
}
.
ClaimSupport
アセンブリは、雑多な共有コードを保持しています。
namespace HynesITe.SharePoint.Authentication.Data {
public static class ClaimSupport {
public static string EventClaimType {
get {
return "http://schema.Company.com/events";
}
}
public static string EventClaimValueType {
get {
return Microsoft.IdentityModel.Claims.ClaimValueTypes.String;
}
}
public static string ApplicationEventKey(string username) {
return username + ":CurrentEvent";
}
public static string ApplicationIssuerKey(string username) {
return username + ":Issuer";
}
public static string ApplicationOriginalIssuerKey(string username) {
return username + ":OriginalIssuer";
}
public static string HeartbeatClaimValue {
get {
return "[heartbeat]";
}
}
}
}
.
ここで本当に重要なことは、私がここにいるようにクレームを操作していて、それらの主張をSharePointによって認識されることを期待していることです。なぜ「ハートビート」を請求します。ほとんどの場合、あなたはそのいずれかを気にしない - クレーム・アグレンダーは正しいことをします - しかしここでは、私はクレームの可能なセットのうちの1つだけを持つ必要があるので、私は中ではなくこのコードで直接操作しなければなりませんでした。クレーム拡張コード。
も知っています。