I've created a Web App project in VS 2015 using default template. and hosted it in Azure. When I run that project it prompts me for the authentication and after hitting sign in button, it goes into infinite loop.
I've found this working couple of times. but most of the time it doesn't work. I put tracing in it keep executing "OpenIDConnectAuthentication" again and again and also, keep adding new entries in TokenCache database. Here is my code for configureAuth.
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
//
// If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
//
AuthorizationCodeReceived = (context) =>
{
Trace.TraceWarning("Authorization Code Received!");
var code = context.Code;
ClientCredential credential = new ClientCredential(clientId, appKey);
string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(authority, new ADALTokenCache(signedInUserID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
return Task.FromResult(0);
}
}
}
);
// This makes any middleware defined above this line run before the Authorization rule is applied in web.config
app.UseStageMarker(PipelineStage.Authenticate);
}
and here is my AdalTokenCache Class:
public class ADALTokenCache : TokenCache
{
private ApplicationDbContext db = new ApplicationDbContext();
private string userId;
private UserTokenCache Cache;
public ADALTokenCache(string signedInUserId)
{
// associate the cache to the current user of the web app
userId = signedInUserId;
Trace.TraceWarning("Logged in User ID: " + userId);
this.AfterAccess = AfterAccessNotification;
this.BeforeAccess = BeforeAccessNotification;
this.BeforeWrite = BeforeWriteNotification;
// look up the entry in the database
Trace.TraceWarning("Total Cached Records " + db.UserTokenCacheList.Count().ToString());
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
// place the entry in memory
this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits,"ADALCache"));
}
// clean up the database
public override void Clear()
{
base.Clear();
var cacheEntry = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
db.UserTokenCacheList.Remove(cacheEntry);
db.SaveChanges();
}
// Notification raised before ADAL accesses the cache.
// This is your chance to update the in-memory copy from the DB, if the in-memory version is stale
void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
if (Cache == null)
{
// first time access
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
}
else
{
// retrieve last write from the DB
var status = from e in db.UserTokenCacheList
where (e.webUserUniqueId == userId)
select new
{
LastWrite = e.LastWrite
};
// if the in-memory copy is older than the persistent copy
if (status.First().LastWrite > Cache.LastWrite)
{
// read from from storage, update in-memory copy
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
}
}
if (Cache == null)
Trace.TraceWarning("Cache is null");
else
Trace.TraceWarning("Cache is not null");
this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache"));
}
// Notification raised after ADAL accessed the cache.
// If the HasStateChanged flag is set, ADAL changed the content of the cache
void AfterAccessNotification(TokenCacheNotificationArgs args)
{
Trace.TraceWarning("After Access Notification!");
try
{
// if state changed
if (this.HasStateChanged)
{
Trace.TraceWarning("1");
Cache = new UserTokenCache
{
webUserUniqueId = userId,
cacheBits = MachineKey.Protect(this.Serialize(), "ADALCache"),
LastWrite = DateTime.Now
};
Trace.TraceWarning("2");
// update the DB and the lastwrite
db.Entry(Cache).State = Cache.UserTokenCacheId == 0 ? EntityState.Added : EntityState.Modified;
Trace.TraceWarning("3");
Trace.TraceWarning("User Token Cache ID:" + Cache.UserTokenCacheId.ToString());
db.SaveChanges();
Trace.TraceWarning("4");
this.HasStateChanged = false;
}
else
Trace.TraceWarning("Cache State not changed");
}
catch (Exception ex)
{
Trace.TraceWarning("Error in After Access Notification: " + ex.Message + "\n" + ex.StackTrace);
}
}
void BeforeWriteNotification(TokenCacheNotificationArgs args)
{
// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
}
public override void DeleteItem(TokenCacheItem item)
{
base.DeleteItem(item);
}
}
How can I troubleshoot to find out what is that making Authentication to go in infinite loop ?
Thanks,
Himal
Himal Patel