| Author |
Share Topic Topic Search Topic Options
|
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Topic: Upgraded to 6.1.7 from 6.1.4 issues migrating multi-domain Authentication code Posted: 13-Jul-2012 at 2:53pm |
Originally posted by DenisK
Hi katit,
Basically, since it's singleton (static) it's a big no-no in multi-tenant application like mine(on server side).......
|
Yes, the Authenticator is not supposed to be used on the server. Instead, you are given a specialized logged in server side EntityManager that you can use.
|
Yes, when code called from SL. In my case it's probably rare use case. I have REST services and need to reuse same database/model. So I just use IB model for that and this is server-only and I need to authenticate on each call. I solved it by obtaining AuthenticationContext and passing it to EntityManager instance on creation.
Edited by katit - 13-Jul-2012 at 2:55pm
|
 |
DenisK
IdeaBlade
Joined: 25-Aug-2010
Posts: 715
|
Post Options
Quote Reply
Posted: 13-Jul-2012 at 12:01pm |
Hi katit,
Basically, since it's singleton (static) it's a big no-no in multi-tenant application like mine(on server side).......
|
Yes, the Authenticator is not supposed to be used on the server. Instead, you are given a specialized logged in server side EntityManager that you can use.
Thank you for your feedback on the documentation. We will review and update it as appropriate.
While solution works - DataSourceExtension is case-sensitive.
|
Yes, this is a bug. It is supposed to be case insensitive. Thank you for reporting it. I'll file a bug report.
Edited by DenisK - 13-Jul-2012 at 12:09pm
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 13-Jul-2012 at 5:46am |
Found another issue related to original post. While solution works - DataSourceExtension is case-sensitive. If I have 2 customers logging into same account and one types "Demo" and another types "demo" I get same exception:
Unable to initialize EntityManager DataSourceExtension cannot be overriden on the server |
So, some place on server it does match strings and in other place doesn't. If I have 2 sessions logging in into different accounts like "demo" and "demo2" everything works. It only gives errors when users login to the same extension with differen case letters in account ID I understand that core issue here is that we end up with URL like this: /EntityServer_demo.svc/sl So, while both users directed to the same endpoint - extention on your server stored AND case-sensitive. Then I get error. Right now I fixed this issue so AccountId I pass is lower-cased
Edited by katit - 13-Jul-2012 at 6:04am
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 12-Jul-2012 at 9:54pm |
Denis, Please update your documentation with explanation about DefaultAuthenticationContext I got pretty lucky, noticed issue right after rolling out update. Basically, since it's singleton (static) it's a big no-no in multi-tenant application like mine(on server side). My bad also for not realizing it but basically I had different customers potentially crossing databases.
Edited by katit - 13-Jul-2012 at 5:58am
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 09-Jul-2012 at 2:45pm |
| If on the client you create an EntityManager with an existing AuthenticationContext, but on the server that session info/user has been removed from the session map due to this inactivity, DevForce will just login again with the encrypted credentials stored in the AuthenticationContext. |
This is exactly what I needed to know. Thanks!
|
 |
DenisK
IdeaBlade
Joined: 25-Aug-2010
Posts: 715
|
Post Options
Quote Reply
Posted: 09-Jul-2012 at 1:21pm |
I assume you meant SessionKey instead of SessionId. Session in this context is the session in which an EntityManager is connected to an EntityServer. It is not a "true" session and again, should not be confused with an ASP.NET session. Session in DevForce is all internal and managed by DevForce.
AuthenticationContext represents such session as well as information about the logged in user. An AuthenticationContext never expires and thus, from the client's perspective, a session never expires as well.
A session info is removed on the server after a period of inactivity as mentioned above. If on the client you create an EntityManager with an existing AuthenticationContext, but on the server that session info/user has been removed from the session map due to this inactivity, DevForce will just login again with the encrypted credentials stored in the AuthenticationContext.
So in effect, the client doesn't see a session info has been removed and in fact, see that nothing has expired.
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 06-Jul-2012 at 12:59pm |
Ok, last question :) You mentioned that there is no expiration on AuthenticationContext. Is there any connection between Session and AuthenticationContext? I see SessionId property. If session expired and I'm creating EntityManager on a client which uses this session - what happens? I'm trying to understand how this will work because it is very hard to test..
|
 |
DenisK
IdeaBlade
Joined: 25-Aug-2010
Posts: 715
|
Post Options
Quote Reply
Posted: 06-Jul-2012 at 12:52pm |
The EntityManager will get garbage collected when it's out of scope.
Note that when I mentioned session info, it's not ASP.NET session info but rather DevForce's own Session Map. The memory consumption here is relatively low and shouldn't cause memory leak.
So to answer your question above, you don't need to call logout every time you're done processing call as EntityManager gets garbage collected and relatively small session info footprints will be cleaned up after a period of inactivity.
Hope this explains it.
Edited by DenisK - 09-Jul-2012 at 1:25pm
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 05-Jul-2012 at 3:30pm |
Ok, so for #4 I have some concerns. In Silverlight I don't really care - clients don't login as much and I can't really control logout because they can just close browser. But I use same EntityManagers for WCF services and there is ton's of calls. I create instance of EntityManager per call. Does it mean that I have to call logout every time after I'm done processing call? I wonder if I can get memory leak by leaving it as it is. Tecnically, after WCF done processing call - EntityManager get's disposed. What about session info?
|
 |
DenisK
IdeaBlade
Joined: 25-Aug-2010
Posts: 715
|
Post Options
Quote Reply
Posted: 05-Jul-2012 at 2:55pm |
Hi katit,
2. There's really no right or wrong answer here on whether to use single sign on/off via DefaultAuthenticationContext. We provide the ability to control this via the EntityManager.Options.UseDefaultAuthenticationContext flag and let developers decide what's best for their applications.
3. No, there's no expiration for AuthenticationContext.
4. Calling Logout will free up session information being stored. If you have a need to do this then yes, in general you should call Logout.
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 05-Jul-2012 at 12:09pm |
I changed client code to look like this:
Authenticator.Instance.LoginAsync( credentials, new LoginOptions(credentials.Domain), loginOperation => { if (loginOperation.CompletedSuccessfully && loginOperation.AuthenticationContext.LoginState == LoginState.LoggedIn) { Authenticator.Instance.DefaultAuthenticationContext = loginOperation.AuthenticationContext; this.OnLoginSuccessfull(); } else if (loginOperation.HasError) { loginOperation.MarkErrorAsHandled(); this.OnLoginError(loginOperation.Error, true); } });
|
When I need new EntityManager I do it like so:
var manager = new MyManager(true, credentials.Domain) |
Questions: 1. Is that correct to manually assign DefaultAuthenticationContext upon logon? 2. Is that correct to create EntityManager relying on DefaultAuthenticationContext? It seems to work. 3. Should I do anything in addition? Is there expiration for AuthenticationContext? If my Silverlight users keep app open whole day, how should I handle this? 4. Should I call Logout at all? In Silverlight - I just block application, is there any good reason why I should logout?
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 03-Jul-2012 at 7:25pm |
Weird. It's working like this :) So, that is working. Now I have question about role of DefaultAuthenticationContext Right now on every view in Silverlight App I'm getting new copy of EntityManager like this:
public EntityManager GetCleanApplicationEntityManager() { var manager = new MyApplicationEntities(this.applicationEntityManager) { DefaultQueryStrategy = QueryStrategy.DataSourceOnly }; manager.VerifierEngine.DefaultVerifierOptions.ShouldTreatEmptyStringAsNull = false; return manager; }
|
Basically, I keep my authenticated EntityManager and create new clean instances to pass around. Should I change the way I create it with a new DefaultAuthenticationContext? If so, how? There is something about expiration in 20 minutes? How should I handle it?
|
 |
DenisK
IdeaBlade
Joined: 25-Aug-2010
Posts: 715
|
Post Options
Quote Reply
Posted: 03-Jul-2012 at 6:48pm |
Hi Katit;
Could you try the following instead?
var context = Authenticator.Instance.Login(credentials, new LoginOptions(accountId)); var applicationManager = new MyApplicationEntities(entityManager, true, accountId);
|
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 03-Jul-2012 at 10:29am |
I also tried to play with new Authenticator and do it like this - pass my accountId(aka dataSourceExtension) via Authenticator
var context = Authenticator.Instance.Login(credentials, new LoginOptions(accountId)); |
Then I modified code to NOT specifically say which dataSourceExtension will be userd
var applicationManager = new MyApplicationEntities(entityManager, true); |
So, this time I did not override it, "magic" entityManager already had proper extension. Still, I'm getting same exception: Unable to initialize EntityManager DataSourceExtension cannot be overriden on the server I also tried to say that server is Local - no luck :(
var context = Authenticator.Instance.Login(credentials, new LoginOptions(accountId, null, EntityServiceOption.UseLocalService)); |
Edited by katit - 03-Jul-2012 at 10:32am
|
 |
katit
Senior Member
Joined: 09-Sep-2011
Posts: 146
|
Post Options
Quote Reply
Posted: 03-Jul-2012 at 9:30am |
I have application where user log's in to his own "Account" each account effectively separate database. I pass AccountId as domain when authenticating. Here is problem I'm trying to solve on a server. I'm using EM on both Silverlight client and WCF server. On server I have code like this:
var credentials = new FormsAuthenticationLoginCredential(userName, password, accountId, false); var context = Authenticator.Instance.Login(credentials);
|
Note I migrated to use Authenticator. On this call it transfers to IEntityLoginManager which looks like this:
public class LoginManager : IEntityLoginManager { private EntityManager entityManager; public LoginManager() { } [Import] public IMembershipService MembershipService { get; set; } public IPrincipal Login(ILoginCredential credential, EntityManager manager) { this.entityManager = manager; if (credential == null) throw new LoginException(LoginExceptionType.NoCredentials, "Credentials required"); return this.CredentialAuthentication(credential); } public void Logout(IPrincipal principal, EntityManager manager) { FormsAuthentication.SignOut(); } private IPrincipal CredentialAuthentication(ILoginCredential credential) { var isAuthenticated = this.MembershipService.ValidateUser(this.entityManager, credential.Domain, credential.UserName, credential.Password); ... } }
| Problem comes in when I call this.MembershipService.ValidateUser(this.entityManager, credential.Domain, credential.UserName, credential.Password); This is my code and I do need to access application database there (remember database is resolved by Key) Code of this method:
public bool ValidateUser(EntityManager entityManager, string accountId, string userName, string password) { var passwordFromDatabase = string.Empty; var passwordSalt = string.Empty; int? failedPasswordAttemptCount = 0; int? failedSecurityAnswerAttemptCount = 0; bool? isActive = false; DateTime? lastActivityDate = DateTime.Now; int? retVal = 0; try { var applicationManager = new MyApplicationEntities(entityManager, true, accountId); applicationManager.MEMGetUserPassword( userName, true, ref passwordFromDatabase, ref passwordSalt, ref failedPasswordAttemptCount, ref failedSecurityAnswerAttemptCount, ref isActive, ref lastActivityDate, ref retVal); var encodedPasswd = EncodeWithSalt(password, passwordSalt); var isPasswordCorrect = passwordFromDatabase.Equals(encodedPasswd); if (isPasswordCorrect && failedPasswordAttemptCount == 0 && failedSecurityAnswerAttemptCount == 0) { return true; } return isPasswordCorrect; } catch (Exception ex) { this.LoggerService.Log(accountId, ex, Category.Exception, Priority.Medium); return false; } }
|
Before it was working, because this "magic" EntityManager was already authenticated to anything and this line worked:
var applicationManager = new MyApplicationEntities(entityManager, true, accountId); |
Now I get exception
Unable to initialize EntityManager DataSourceExtension cannot be overriden on the server |
So, how do I authenticate using only 1 model without resorting to use plain ADO? I have data extention, I have SourceKeyResolver which does what I need. I had it working before. How do I make it work with new authentication?
|
 |