Print Page | Close Window

Multi-tenant Login

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3614
Printed Date: 13-May-2026 at 4:36am


Topic: Multi-tenant Login
Posted By: halloweenx8
Subject: Multi-tenant Login
Date Posted: 07-Sep-2012 at 5:36pm
I'm new to DevForce 6.1.7.1 with Cocktail 0.6.3 and i'm trying to implement a Multi-tenant Login for our new application, and i'm having some difficulties.

here is how it is suppose to work (high level)

1. User get to an ASPX page and asked for a code (not a password) and a user name
    with this code i can get to the tenant database 
2. I validate that the code is right and then prompt the user for a password (still in aspx)
3. when i have these 3 things i can log in
    a) user code to get the database name (and build the connection string with it) 
    b) then use that connection string and validate the username/password
4. when the authentication works, i load a silverlight app

Here is the problem
I can Successfully validate the user code and get the connection string but for the life of me i cannot validate the username and password, i cannot connect the the customer's user database.  

Here is some code

public class AppNameAuthentication : AuthenticationService, IUserService {
regular suff
}


public virtual IPrincipal Login(ILoginCredential credential, EntityManager entityManager)
{
    if (credential == null)
        throw new LoginException(LoginExceptionType.NoCredentials, "Credentials are required.");
           
    if (string.IsNullOrWhiteSpace(credential.UserName))
        throw new LoginException(LoginExceptionType.InvalidUserName, "Username cannot be emptys.");

    if (string.IsNullOrWhiteSpace(credential.Password))
        throw new LoginException(LoginExceptionType.InvalidPassword, "Password cannot be empty.");

    var em = new SecurityEntities(entityManager);

    User user = em.Users.FirstOrDefault(u => u.UserId == credential.UserName );

    if (user == null)
        throw new LoginException(LoginExceptionType.InvalidPassword, credential.Domain, credential.UserName);

    return new UserPrincipal(user.Id, new UserIdentity(user.UserId, user.ProfileUID.ToString(), true));
}

--   var em = new SecurityEntities(entityManager);
this does not user the created connection string but it should.


Thanks for the help






Replies:
Posted By: mgood
Date Posted: 08-Sep-2012 at 9:43am
There's a recent discussion topic over in the Cocktail forum about how to connect to different databases at runtime. This might answer your questions.

http://www.ideablade.com/forum/forum_posts.asp?TID=3449&title=manual-custom-connection-without-having-to-leave-the-application - http://www.ideablade.com/forum/forum_posts.asp?TID=3449&title=manual-custom-connection-without-having-to-leave-the-application

BTW, you may want to upgrade to Cocktail v1.0


Posted By: halloweenx8
Date Posted: 09-Sep-2012 at 10:06am
I did upgrade to Cocktail v1.0 and DevForce 6.1.8.1 , now i'm getting 

Error 4 The "EntityModelMetadataDeploy" task failed unexpectedly.
System.IO.FileNotFoundException: Could not load file or assembly 'IdeaBlade.VisualStudio.DTE, Version=6.1.8.0, Culture=neutral, PublicKeyToken=287b5094865421c0' or one of its dependencies. The system cannot find the file specified.
File name: 'IdeaBlade.VisualStudio.DTE, Version=6.1.8.0, Culture=neutral, PublicKeyToken=287b5094865421c0'

Server stack trace: 
   at IdeaBlade.VisualStudio.Build.Tasks.EntityModelMetadataDeploy.Execute()
   at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs)
   at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Microsoft.Build.Framework.ITask.Execute()
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__20.MoveNext()

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

When i compile, any toughts?



Posted By: mgood
Date Posted: 09-Sep-2012 at 10:27am
The downloaded binaries were built with 6.1.8, not 6.1.8.1. 6.1.8.1 is a hotfix that addresses one specific issue that only affects you if your model uses composite foreign keys. We'll push out an update that will work with 6.1.8.1, but in the meantime, install 6.1.8. You can find the installer in the full download package here:
 
http://cocktail.codeplex.com/releases/view/92595 -


Posted By: halloweenx8
Date Posted: 09-Sep-2012 at 12:36pm
great now that's working... but some else is happening, and only when i start my application

I cleared up the C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/root folder to be sure, but it is still happening

[FileNotFoundException: Could not load file or assembly 'IdeaBlade.Core, Version=6.1.8.0, Culture=neutral, PublicKeyToken=287b5094865421c0' or one of its dependencies. The system cannot find the file specified.]

[FileNotFoundException: Could not load file or assembly 'IdeaBlade.Core, Version=6.1.8.1, Culture=neutral, PublicKeyToken=287b5094865421c0' or one of its dependencies. The system cannot find the file specified.]
   WebRole1.Default.BtnSigninClick(Object sender, EventArgs e) in \WebRole1\Default.aspx.cs:26
   System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +155
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3804

Why is it trying to redirect to 6.1.8.1 i did uninstall it and reinstall 6.1.8.0

Strang things are happening :-(


Posted By: mgood
Date Posted: 09-Sep-2012 at 2:05pm
Delete all the bin folders. You can use the flush.cmd that comes with Cocktail. Then rebuild. Looks like you have something old hanging around. Also, make sure that the IdeaBlade assemblies have Copy Local set to true.


Posted By: halloweenx8
Date Posted: 09-Sep-2012 at 3:57pm
I found the problem,
 
in my web.config i had these lines
<dependentAssembly>
        <assemblyIdentity name="IdeaBlade.EntityModel" publicKeyToken="287b5094865421c0" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.1.8.1" newVersion="6.1.8.1" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="IdeaBlade.Core" publicKeyToken="287b5094865421c0" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.1.8.1" newVersion="6.1.8.1" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="IdeaBlade.Validation" publicKeyToken="287b5094865421c0" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.1.8.1" newVersion="6.1.8.1" />
      </dependentAssembly>
 
By removing them the app is back online, thanks
 
now back to the original problem:
[LoginException: Credentials are required.]
 
I need to get to the database to get some information about the customer that logs in so I can tell what database to connect to to authenticate the user.
 
Is there a way to get the the database without being authenticated?
 


Posted By: mgood
Date Posted: 09-Sep-2012 at 4:13pm
There are two options. The first option is by means of an anonymous user. An anonymous user is a user that isn't authenticated, meaning you set isAuthenticated to false in the identity. So, when the credentials are null, you return the Anonymous user from the LoginManager. Then you should secure all your business entities, other than the once that give you the information you need, by marking them with the RequiresAuthenticationAttribute, so that the anonymous user cannot query any of them.
 
The other option is to use a system user that only the server knows about. I don't like this option very much, because you have to store the password somewhere.


Posted By: halloweenx8
Date Posted: 09-Sep-2012 at 6:45pm
HO YEAHHHHHHHHHH  that worked...
 
Thank you very much for your help.  Keep up the good work.


Posted By: halloweenx8
Date Posted: 10-Sep-2012 at 8:14pm
Still doing authentication :-)
 
Now i have all the info I need so i call the login manager
 
 authentication.Login(new LoginCredential(username, password, domain);
 
this call cocktail's AuthenticationService.Login which in turn calls my LoginManager
 
   public virtual IPrincipal Login(ILoginCredential credential, EntityManager entityManager)
 
in that code i call
    var em = new SecurityEntities(entityManager, true, credential.Domain);
 
the credential.domain is actually the tenant ID, and i need the tenant ID for  IDataSourceKeyResolver tso i can get to the right database for authentication but i get this
 
Unable to initialize EntityManager
DataSourceExtension cannot be overriden on the server 
 
I tried  not using the provided EntityManager and creating a new one but i get "Implicit login is not allowed when the AuthenticationContext is logged out."
 
This thing is somewhat complicated :-0
 


-------------
Jean

"If You are Not Making Mistakes, then You are Not Doing Anything.”


Posted By: mgood
Date Posted: 10-Sep-2012 at 8:41pm
You have to set the DataSourceKeyExtension on the client by configuring the AuthenticationService with proper ConnectionOptions. You can't do that on the server in the LoginManager or you'll get into a chicken or the egg problem. First as you discovered, you can't override the DataSourceExtension on the server. If you try to new up an EntityManager it needs to be logged in, but you are in the LoginManager, so that would result in an endless loop.





Print Page | Close Window