Custom Forms Authentication in MVC 4, .Net 4.5 - asp.net-mvc

I am posting this here after exhausting out every possible solution that could resolve the issue I am facing with my custom implementation of Forms Authentication. To give you a background of what I did so far... I was trying to implement the accepted solution from the following thread.. ASP.NET MVC - Set custom IIdentity or IPrincipal
So, I changed my Web.Config to allow for forms authentication. This redirects the user to the login page when the first request comes in. This is how my Web.Config looks right now.
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="Account/login" timeout="30" slidingExpiration="true"></forms>
</authentication>
<httpModules>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
</httpModules>
</system.web>
In the controller after the user is validated...
Dim serializer = New JavaScriptSerializer()
Dim serializableModel = New With {
.SchoolYearId = _userModel.SchoolYearId,
.AccessLevel = _userModel.AccessLevel,
.UserId = _userModel.UserId,
.FirstName = _userModel.FirstName,
.LastName = _userModel.LastName,
.SchoolYear = _userModel.SchoolYear,
.Role = _userModel.Role
}
'.Identity = _userModel.Identity
Dim userData As String = serializer.Serialize(serializableModel)
Dim authenticationTicket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, _userModel.UserId, DateTime.Now, DateTime.Now.AddMinutes(15), False, userData)
Dim encTicket As String = Security.FormsAuthentication.Encrypt(authenticationTicket)
Dim faCookie As HttpCookie = New HttpCookie(Security.FormsAuthentication.FormsCookieName, encTicket)
Response.Cookies.Add(faCookie)
Return RedirectToAction("Add")
Now in the global.asax file, in the post authenticate section..
Dim authCookie As HttpCookie = Request.Cookies(System.Web.Security.FormsAuthentication.FormsCookieName)
If (Not IsNothing(authCookie)) Then
Dim authTicket As FormsAuthenticationTicket = System.Web.Security.FormsAuthentication.Decrypt(authCookie.Value)
Dim serializer = New JavaScriptSerializer()
Dim deSerializedModel = serializer.Deserialize(Of UserModel)(authTicket.UserData)
Dim userModel As IUserModel = New UserModel
userModel.SchoolYear = deSerializedModel.SchoolYear
userModel.SchoolYearId = deSerializedModel.SchoolYearId
userModel.AccessLevel = deSerializedModel.AccessLevel
userModel.UserId = deSerializedModel.UserId
userModel.FirstName = deSerializedModel.FirstName
userModel.LastName = deSerializedModel.LastName
userModel.SchoolYear = deSerializedModel.SchoolYear
userModel.Role = deSerializedModel.Role
HttpContext.Current.User = userModel
End If
So, once the user the authenticated, the code goes through the postauthenticaterequest block and right after it exits the postauthenticaterequest block, the following error pops up which has been driving me crazy.
http://imgur.com/a/XGMnb
I did go through some of the problems that other users faced but this is something I couldnt find much help on. How do I go about solving this? This happens locally and not the webserver.

Related

User Lockout Doesn't work if the user doesn't have an email id MVC 5

I am trying to lockout a user after n number of unsuccessful attempts and this only works if the user has an email id and i am using username instead of an email id to login into my application.In this scenario is there a way i can lockout the user without an email id too ?
You could try the keeping a failure counter in a session variable. You will need to add session state to web.config to use this code though.
In your controller
public int getFailedAttempts()
{
int? failedAttempts = Session["FailedAttempts"] as int?;
if (failedAttempts != null)
{
return (int)failedAttempts;
}
else {
return 0;
}
}
public void handleFailedAttempt()
{
var failedAttempts = getFailedAttempts();
Session["FailedAttempts"] = failedAttempts + 1;
}
In web.config
<system.web>
...
<sessionState mode="InProc" timeout="30" />
</system.web>

How to set Password and Username in web.config

In my MVC Application I use the connection string is set in the Web.config via
Private connectionString As String = ConfigurationManager.ConnectionStrings("DBCS").ConnectionString
and have no problems with my db connection. But since I need a password and username to log into my database I hardcoded that in the web.config
<connectionStrings>
<add name="DBCS" connectionString="server=win\SQLExpress;database=myDb; uid=myUsername;password=myPassword" providerName="System.Data.SqlClient" />
</connectionStrings>
I am looking for a way to send the password and username from the userinterface to the config.web file first off I thought the ConfigurationManager Class should provide a property for that but I cannot find something. Can anyone explain to me how to do this?
You can save this value in app settings:
<appSettings>
<add key="DBCS" value="Data Source=win\SQLExpress;Initial Catalog=myDb;User ID={0};Password={1}" />
</appSettings>
and then do the following:
using System.Data.SqlClient;
public void DoDatabaseOperations(string _Username, string _Password)
{
string connetionString = null;
SqlConnection cnn ;
connetionString = string.Format(ConfigurationManager.AppSettings("DBCS"), _Username, _Password);
cnn = new SqlConnection(connetionString);
try
{
cnn.Open();
// your code here
cnn.Close();
}
catch (Exception ex)
{
// handle exception
}
}
VB.NET Equivalent:
Imports System.Data.SqlClient
Public Sub DoDatabaseOperations(_Username As String, _Password As String)
Dim connetionString As String = Nothing
Dim cnn As SqlConnection
connetionString = String.Format(ConfigurationManager.AppSettings("DBCS"), _Username, _Password)
cnn = New SqlConnection(connetionString)
Try
cnn.Open()
' your code here
cnn.Close()
' handle exception
Catch ex As Exception
End Try
End Sub

Asp.net Telerik MVC 4 Application with Unit Test Project

I created a Asp.net Telerik MVC 4 Application that has a unit project in it. When I tried to initialize a user object in the unit test, it failed. It gave an error message that said the connection string does not exist in the config file. However, I check the config file, and the connection string is there.
here are some sample codes:
//Connection String
<connectionStrings>
<add name="KMSSEntities" connectionString="metadata=res://*/Models.KMSSEntityModel.csdl|res://*/Models.KMSSEntityModel.ssdl|res://*/Models.KMSSEntityModel.msl;provider=System.Data.SqlClient;provider connection string="data source=(local);initial catalog=KMSS;persist security info=True;user id=******;password=*******;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
//Initialize my Context
private KMSSEntities entity = new KMSSEntities();
//This is my insert user
public void InsertUser(User user)
{
entity.Users.Add(user);
}
//this is code in the test method
User u = new User();
u.UserName = "test";
u.password = "Password";
u.FirstName = "first";
u.LastName = "Last";
StudentRepository rep = new StudentRepository(new KMSSEntities());
rep.InsertUser(u); **//This is where it's returning the error message**
rep.Save();
//This is the stack trace.
at System.Data.Entity.Internal.LazyInternalConnection.get_ConnectionHasModel()
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)
at System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity)
at System.Data.Entity.DbSet`1.Add(TEntity entity)
at KMSS.Models.UserRepository.InsertUser(User user) in c:\com\KMSS\KMSS\KMSS\Models\UserRepository.cs:line 29
at KMSSTests.UnitTest1.TestMethod1() in c:\com\KMSS\KMSS\KMSSTests\UnitTest1.cs:line 21

ASP.NET MVC 3 + Windows Authentication + Database Login check

I need some insight on the proper way to setup an ASP.NET MVC 3 web app where the users are logged in two ways:
They are part of the Domain (Windows Authentication)
The application's user table/store says they have access to the application
To handle the first requirement I am setting the authenication element to Windows in the web.config:
<authentication mode="Windows" />
The second one is the one that is a bit trickier. My current thought was to utilize the HttpApplications AuthenticationRequested event. So the code might look something like this:
void MvcApplication_AuthenticateRequest( object sender, EventArgs e )
{
var formsAuthTicket = GetFormsAuthTicket();
if ( formsAuthTicket == null || formsAuthTicket.Expired )
{
var userHasAccess = true; //TODO: Ask the someone if the user has access
if ( userHasAccess )
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1,
HttpContext.Current.User.Identity.Name,
DateTime.Now,
DateTime.Now.AddMinutes( 1 ),
true,
HttpContext.Current.User.Identity.Name );
string encTicket = FormsAuthentication.Encrypt( authTicket );
this.Response.Cookies.Remove( FormsAuthentication.FormsCookieName );
this.Response.Cookies.Add( new HttpCookie( FormsAuthentication.FormsCookieName, encTicket ) );
}
else
throw new HttpException( 401, "User is not authorized" );
}
}
Any thoughts?
I think there is better way to implement it in ASP.NET MVC by creating global authorization filter

F# Asp.Net CodeDom ProviderOptions Issue

I'm creating an ASP.NET MVC application using F# on IIS 7.
When I attempt to run it from the browser, I'm met with a YSOD containing the following:
[ArgumentNullException: Value cannot
be null. Parameter name: dictionary]
System.Collections.Generic.Dictionary2..ctor(IDictionary2
dictionary, IEqualityComparer`1
comparer) +12700827
System.Web.Compilation.CompilationUtil.CreateCodeDomProviderWithPropertyOptions(Type
codeDomProviderType) +84
System.Web.Compilation.CompilationUtil.CreateCodeDomProviderNonPublic(Type
codeDomProviderType) +16
System.Web.Compilation.AssemblyBuilder..ctor(CompilationSection
compConfig, ICollection
referencedAssemblies, CompilerType
compilerType, String
outputAssemblyName) +469
System.Web.Compilation.CompilerType.CreateAssemblyBuilder(CompilationSection
compConfig, ICollection
referencedAssemblies, String
generatedFilesDir, String
outputAssemblyName) +127
System.Web.Compilation.BuildProvidersCompiler.ProcessBuildProviders()
+675 System.Web.Compilation.BuildProvidersCompiler.PerformBuild()
+46 System.Web.Compilation.ApplicationBuildProvider.GetGlobalAsaxBuildResult(Boolean
isPrecompiledApp) +11321455
System.Web.Compilation.BuildManager.CompileGlobalAsax()
+50 System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled()
+872
I looked up the method using Reflector to see if it could give me any more context and found that it was failing on the first line
private static CodeDomProvider CreateCodeDomProviderWithPropertyOptions(Type codeDomProviderType)
{
IDictionary<string, string> providerOptions = new Dictionary<string, string>(GetProviderOptions(codeDomProviderType));
//Snip
}
It leads me to believe that the propertyOptions I've specified in my Web.config for the F# CodeDom are incorrect. However, if I remove them I receive the same error.
<system.codedom>
<compilers>
<compiler language="F#;f#;fs;fsharp" extension=".fs" warningLevel="4"
type="Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider,
FSharp.Compiler.CodeDom">
<providerOption name="CompilerVersion" value="v4.0"/>
<providerOption name="WarnAsError" value="false"/>
</compiler>
</compilers>
</system.codedom>
Any ideas on correcting this error?
It’s a bug in ASP.NET in VS2010 Beta2 (it has since been fixed, so will work in next release). It affects any 3rd party CodeDOM provider, and I don’t believe there is any workaround.
I found the cause to the problem.
The Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider.FileExtension is hardcoded to "fs".
Inside of System.CodeDom.Compiler.CodeDomCompilationConfiguration..ctor() CompilerInfos are created for each of the allowed languages. A CompilerInfo for FSharp is not found within the creation of this.
internal CodeDomCompilationConfiguration()
{
this._compilerLanguages = new Hashtable(StringComparer.OrdinalIgnoreCase);
this._compilerExtensions = new Hashtable(StringComparer.OrdinalIgnoreCase);
this._allCompilerInfo = new ArrayList();
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.WarningLevel = 4;
string codeDomProviderTypeName = "Microsoft.CSharp.CSharpCodeProvider, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
CompilerInfo compilerInfo = new CompilerInfo(compilerParams, codeDomProviderTypeName);
compilerInfo._compilerLanguages = new string[] { "c#", "cs", "csharp" };
compilerInfo._compilerExtensions = new string[] { ".cs", "cs" };
compilerInfo._providerOptions = new Dictionary<string, string>();
compilerInfo._providerOptions["CompilerVersion"] = "v4.0";
this.AddCompilerInfo(compilerInfo);
compilerParams = new CompilerParameters();
compilerParams.WarningLevel = 4;
codeDomProviderTypeName = "Microsoft.VisualBasic.VBCodeProvider, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
compilerInfo = new CompilerInfo(compilerParams, codeDomProviderTypeName);
compilerInfo._compilerLanguages = new string[] { "vb", "vbs", "visualbasic", "vbscript" };
compilerInfo._compilerExtensions = new string[] { ".vb", "vb" };
compilerInfo._providerOptions = new Dictionary<string, string>();
compilerInfo._providerOptions["CompilerVersion"] = "v4.0";
this.AddCompilerInfo(compilerInfo);
//Snip
}
The FileExtension is compared against _compilerExtensions in System.CodeDom.Compiler.CodeDomProvider.GetCompilerInfoForExtensionNoThrow which (in the case of "fs") returns null to System.CodeDom.Compiler.CodeDomProvider.IsDefinedExtension which will then return false to System.Web.Compilation.CompilationUtil.GetProviderOptions that returns the null that was causing the ArgumentNullException.
Thanks for pointing me in the right direction, #Brian
Perhaps the bug Brian noted can be worked around by specifying some more info in web.config:
type="Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider,
FSharp.Compiler.CodeDom,
Version=1.9.7.8,
Culture=neutral,
PublicKeyToken=a19089b1c74d0809"

Resources