How to get ClientCertificate from the request (comparing ASP.NET and Silverlight) - c#

I have a Silverlight Web Application which uses Silverligh-enabled WCF service for getting datas from other Web-Services and Database. In the previous, end users signing in to the web site by writing their UserName and Password to the TextBoxes and clicking button. Now, end users have a card and a card reader. Certification prompt must be appeared after entering the web site. So, I have changed my web service and it uses HTTPS. And in IIS I set SSL Settings to Require for the Web Site. Of course, I have created Web Site certificate also and set the binding's certificate to it. Everything works fine now. The web site and the web service are opening with HTTPS. Also, certification prompt is displaying whenever entering to the Web Site. And after all certificates are shown in the list, user must choose one of them. After that he must enter his password and if data in the certificate store is same with the card in card reader, the webSite is opening.
I have read this article for configuring web Service to use HTTPS.
In ASP.NET we are getting certificate like that:
X509Certificate2 cert = new X509Certificate2(Request.ClientCertificate.Certificate);
string subject = Request.ClientCertificate.Subject;
if (!Request.ClientCertificate.IsValid || Request.ClientCertificate.Count == 0)
{
// failed
}
else
{
Session["isRegistered"] = true;
// success
}
But I dont know how to get certificate from the request with Web Service.
Thanks.

Looks like what the best option for you would be to implement a custom Certificate Validator for your service. This is basically a class that derives from X509CertificateValidator and is then registered through the config file.
There's more complete information on how to do this on this article.

You can find the security context of the WCF request in the System.ServiceModel.OperationContext.Current object, especially in the ServiceSecurityContext field.

I think that, I have solved the problem. I sent ClientCertificate property of request object from Asp.net to Silverlight like that:
<form id="form1" runat="server" style="height:100%">
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
...
<param name="initParams"
value="ClientCertificate=<%=Request.ClientCertificate.Subject %>, cc=true, m=/relative" />
...
</form>
And in App.xaml.cs I am getting values in Application_startup event:
private void Application_Startup(object sender, StartupEventArgs e)
{
if (e.InitParams != null)
{
foreach (var item in e.InitParams)
{
this.Resources.Add(item.Key, item.Value);
}
}
this.RootVisual = new MainPage();
}

Related

How to integrate nancy with asp.net Form based authentication

We are in process to migrate our asp.net based application to nancy, as Application is quite big, so we have decided to make application hybrid & migrate it to nancy page by page.
Now we have a nancy login screen, using which we need to do asp.net form authentication as well. Can someone guide us how can we authenticate user with asp.net form based authentication in nancy code.
We are planning to use stateless authentication on nancy side.
Any pointer is highly appreciated.
We are having a nancy login page to validated user credentials
1. Login Module -
Post["/login"] = p =>
{
// Verify user crdentials first
// Success, create non-persistent authentication cookie.
System.Web.Security.FormsAuthentication.SetAuthCookie(credentials.tbUser, false);
var cookie = System.Web.Security.FormsAuthentication.GetAuthCookie(credentials.tbUser, false);
cookie.Expires = DateTime.UtcNow.AddHours(5);
HttpContext.Current.Response.Cookies.Set(cookie);
return Response.AsRedirect("~/listRequest.aspx"); // used Nancy's redirect model to navigate to another page
}
2. Global.asax -
void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
FormsIdentity fIdent = application.Context.User.Identity as FormsIdentity;
if (fIdent != null) **// It always returns null even after ".ASPXAUTH" cookie is successfully created**
{
FormsAuthenticationTicket ticket = fIdent.Ticket; // to see if the ticket exists
}
}
One of the ideas I have not tested but seems likely to be is to use the LoginWithoutRedirect method of Nancy.Authentication.Forms.
Your application will manage authentication cookies for ASP.NET and authentication cookies for Nancy Forms at the same time.

Spotify authorization code flow (WPF browser control) C#

I'm using Spotify account service (authorization code flow) to get an authorization code by passing in the required parameters (client_id, response_type and redirect_uri. Its a WPF application so i am using the browser control and navigating the user to
https://accounts.spotify.com/authorize/?client_id=myclientId&response_type=code&redirect_uri=someUri
When i copy paste the link in the browser, i see the right stuff i.e page with the Login to Spotify button but when i am navigating through the browser control in my WPF application, it gives me a file download dialog with Authorize.json file to download with Open and Save options, however in some cases it presents the right page to browser code.
Below is my code:
public winOAuthBrowserForm(string navigateTo)
{
InitializeComponent();
webBrowser.Navigated += webBrowser_Navigated;
webBrowser.Navigate(navigateTo);
}
private void webBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
if(!String.IsNullOrEmpty(e.Uri.Query))
{
//since we are looking for code for authorization that will be exchanged for request token from the server
if (e.Uri.Query.StartsWith("?code=") || e.Uri.Query.Contains("code="))
{
code = HttpUtility.ParseQueryString(e.Uri.Query).Get("code");
this.Close();
}
if (e.Uri.Query.StartsWith("?error=") || e.Uri.Query.Contains("error="))
{
error = HttpUtility.ParseQueryString(e.Uri.Query).Get("error");
this.Close();
}
}
}
And i am calling this control like:
var uri = string.Format(SpotifyAuthUriFormatter, RequestAuthBaseUrl, clientId);
winOAuthBrowserForm form = new winOAuthBrowserForm(uri);
form.ShowDialog();
This is what i see:
UPDATE: When i right click on document and see the properties, i see it changes the URL to something like res://ieframe.dll/navcancl.htm#... I've searched it and found some solutions related to I.E (I'm using latest but you can't be sure that it'll be latest on client machines), some say that its firewall setting. The thing is, it appears sometimes only.
Any ideas? Thanks

Basic authentication on a remote server

I need some help with ASMX web-services.
Let's suppose I have a ServerService which provides some data. Let's suppose it has a method GetRandomInteger which returns a random integer (obviously). It implements a custom basic authentication using IHttpModule.
public class BasicAuthHttpModule : IHttpModule
{
private UserRepository _userRepository;
public void Dispose()
{
}
public void Init(HttpApplication application)
{
_userRepository = new UserRepository();
application.AuthenticateRequest += OnAuthenticateRequest;
application.EndRequest += OnEndRequest;
}
public void OnAuthenticateRequest(object source, EventArgs e)
{
var app = (HttpApplication)source;
string authHeader = app.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authHeader))
{
// Here I successfully get credentials from header
if (_userRepository.ValidateUser(username, password)) return;
// Return 401 and CompleteRequest
}
else
{
// Return 401 and End
}
}
public void OnEndRequest(object source, EventArgs eventArgs)
{
if (HttpContext.Current.Response.StatusCode == 401)
{
// Return 401 and require new authorization
}
}
Fortunately, it works. Now I can successfully open Service.asmx file, get basic authentication window and get access to it's GetRandomInteger method after successful authentication.
Now I have an ASP.NET MVC 4 application called ClientService. It must provide user interface with convenient and appropriate access to methods of ServerService. Now it has default controllers like Account and Home, default views etc.
I need this ClientService to authenticate on a ServerService. I mean there will be a Home/Index page with button "Login". I enter login and password there and ClientService tries to authenticate at ServerService. It returns error on fail or authenticates on success providing access to some Home/RandomInt page which will show the integer requested from ServerService. What is the best and the easiest way to do this?
How to implement registration on a ServerService? There is no AllowAnonymous attribute or something at ASMX, so I can't register user because he doesn't have access to any of methods due to 401 error.
Thank you in advance.
P.S. No. I can't use WCF or something else. I need to implement an ASMX web-service.
Update 1: OK, I have learned something new from here
http://www.aspsnippets.com/Articles/How-to-add-reference-of-Web-Service-ASMX-in-ASPNet-using-Visual-Studio.aspx
There is an old-style thing like "Web reference" and it's not an "Service reference". I have added this Web reference to my project and now I can call some methods from this ASMX page in this way:
try
{
ServerService svc = new ServerService();
svc.Credentials = new NetworkCredential("user", "password");
int a = svc.GetRandomInteger();
} catch (WebException e) {
// Auth failed
}
However, I don't understand how to link it with ASP.NET MVC ClientService authentication. So, both questions are still open. Hopefully, I will understand it or you will help me.
Here is a documentation for adding a Web reference to an ASMX Service.
http://www.aspsnippets.com/Articles/How-to-add-reference-of-Web-Service-ASMX-in-ASPNet-using-Visual-Studio.aspx
Using this information I can easily make requests to a web service.
The only thing I left to do on the moment of question update is to create a custom authentication.
When user logins, the client sends a request to a service. In case of successful basic authentication, it creates proper FormsAuthentication cookie ticket for a user. User logs in.
On each request to a service, the client extracts login from FormsAuthentication cookie and his password from server cache and uses them to authenticate on a service. In case of basic auth failure (it can only occur if user's password has been changed on the service side) the cookie is cleared and session is aborted.
Registration is implemented using another one ASMX service which is not using basic auth but is anonymous (because registration is supposed to be anonymous method).
That's it. Finally, I have found a proper solution :)

Postback Fails On Default Document

So I've created a Web Application (not Web Site) with ASP.NET (C#) and it compiles just fine in the VS13 environment. But when I publish it on IIS, the Postback on the Default Document fails. The Default Document is called LoginPage.aspx. As soon as I click the <asp:Button> to run my code behind, all it does is refresh the page. This project has been published on my local 127.0.0.1 IP address for the time being.
I know this has been a documented issue, but I've tried many solutions and have not come across a resolution. Some solutions I have attempted:
Creating a brand new Web App with minimal code to attempt accessing any Postback with no success.
I tried the first solution presented here with no success: https://stackoverflow.com/a/7367076/4204026
I also tried URL mappings:
<urlMappings>
<add url="~/login" mappedUrl="~/Views/LoginPage.aspx" />
<add url="~/login/" mappedUrl="~/Views/LoginPage.aspx" />
</urlMappings>
I'm honestly at a loss as to what's happening here. One thing I did notice is when the application is being run through Visual Studio, the <form> tag on the LoginPage.aspx appears in Chrome as:
<form method="post" action="LoginPage" id="ct101" class=".myForm">
Through IIS:
<form method="post" action="./" id="ct101" class=".myForm">
Not sure if that's a problem either. I tried hard-coding the action to login to see what would happen and it does redirect to the correct page, but as suspected no Postback was fired - My Session variable returned null and no query string was used.
Here's the related LoginPage.aspx front-end code (trimmed out a bunch of unrelated HTML):
<%# Page Title="DREW KENNEDY | WELCOME" Language="C#" MasterPageFile="Site.Master" AutoEventWireup="true" CodeBehind="LoginPage.aspx.cs" Inherits="MyMedia.Views.LoginPage" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<!-- form is located on Site.Master -->
<asp:Button OnClick="LoginBtn_Click" CssClass="login" runat="server" name="submit" Text="Sign In" />
</asp:Content>
And the LoginBtn_Click method in LoginPage.aspx.cs:
protected void LoginBtn_Click(object sender, EventArgs e) {
//Tried the following line while commenting out everything else to make sure Postback is being ignored
//Response.Write("<script>alert('Test');</script>");
try {
AbstractPersistenceDecorator decorator = new PersistenceDecorator();
string uname = username.Text.Trim();//username is a TextBox Control
string pass = password.Text.Trim();//password is a TextBox control
bool isCookieRequested = CheckBox.Checked;
if (decorator.authenticate(uname, pass)) {//calling SQL Server for authentication
User AuthenticatedUser = (User)Session["User"] ?? decorator.getUserInfo(uname);
if (Session["User"] == null) Session["User"] = AuthenticatedUser;
if (isCookieRequested) {
HttpCookie cookie = new HttpCookie("username", AuthenticatedUser.Username);
cookie.Expires.AddDays(7);
Response.Cookies.Add(cookie);
} else {
Session.Timeout = 15;
}
Thread.Sleep(1600);
//string redirect = string.Format("dashboard?username={0}", AuthenticatedUser.Username);
Response.Redirect("dashboard?username=" + AuthenticatedUser.Username);
}
} catch (Exception ex) {
//who cares?
}
}
Final pieces of info:
Running IIS 8.0
Application created with 4.5 Framework, Application Pool is also 4.5 Framework
I have ensured that ASP.NET is installed on IIS
I do have URL ReWriting in the global.asax file, though I'm not sure if that is related in any way (I don't see how).
I have no Default.aspx page
EDIT:
Just tested the project through 127.0.0.1 on IE11 and FF with the same result.
EDIT #2:
Additional things I have tried with no success:
I tried removing my URL Rewriting
I tried adding an empty URL Rewrite rule, i.e. ("Empty URL", "", "~/Views/LoginPage.aspx")
Additional notes:
I do not use Telerik
I do not use ISAPI
The project in Visual Studio was set to debug and not release
I apologize for not giving enough information in the OP as I have found the answer. It turns out it had nothing to do with ASP.NET, but rather SQL Server. I stripped the code bare and after adding back one piece of code at a time and stripping away all exception handling, I found through IIS that IIS APPPOOL\.NET vX.X did not have permissions to access the database.
What I had to do is:
In MSQLSM, add a new Login for IIS APPPOOL\.NET v4.5
Further on, I found out that it needed the correct permissions to perform certain commands after receiving the following exception:
The SELECT permission was denied on the object 'X', database 'X', schema 'dbo'
This Was Solved Here
Give that new Login the proper access. Login Properties > User Mapping > checking db_datareader and public.
The code behind now executes. It still leaves the question why it was prohibiting any Postbacks, even if I removed any SQL Connectivity in the code behind. Very strange.
Anyway, thanks to those who helped.
I suggest that you redirect from the default page to the Expected page then this should work. Iis default page handling is done through isapi to handle static content so the post data may not survive

reCaptcha and SSL web site

I using a reCaptcha on my web page under asp.net mvc. This web site have a SSL certificated, and I having and problem with reCaptcha.
This is my code on View:
<script type="text/javascript" src="https://api-secure.recaptcha.net/challenge?k=***Public key****"> </script>
<noscript>
<iframe src="https://api-secure.recaptcha.net/noscript?k=***Public key****" height="300" width="500" frameborder="0"></iframe><br />
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge" />
</noscript>
and this code is that I have on AccountController:
private bool PerformRecaptcha()
{
var validator = new RecaptchaValidator
{
PrivateKey = "**Private Key***",
RemoteIP = Request.UserHostAddress,
Response = Request.Form["recaptcha_response_field"],
Challenge = Request.Form["recaptcha_challenge_field"]
};
try
{
var validationResult = validator.Validate();
if (validationResult.ErrorMessage == "incorrect-captcha-sol")
ModelState.AddModelError("ReCaptcha", string.Format("Please retry the ReCaptcha portion again."));
return validationResult.IsValid;
}
catch (Exception e)
{
ModelState.AddModelError("ReCaptcha", "an error occured with ReCaptcha please consult documentation.");
return false;
}
}
and my library version is 1.0.5.0.
When I load the register form I have this alert on Opera:
The rules server certificate matches the server name. Do you want to accept?
If I accept this certificate, displays reCaptcha code, but if not, I don't view reCaptcha Code.
Can you help me with this?
If you need more information about my code, feel free to ask to me.
Regards.
I think you need to change the url you are using to include recaptcha. A number of people had the same problem in April. Recaptcha let the certificate expire for "api-secure.recaptcha.net". If you change it to use the "https://www.google.com/recaptcha/api/XXX" url instead of "https://api-secure.recaptcha.net/XXX", it should definitely fix your issue.
It looks like this one has actually been answered before: recaptcha https problem on https://api-secure.recaptcha.net/. Since you are using the .NET library, I think your answer is to upgrade your version.
Sharpening up on JasonStoltz's answer:
You are already using the latest DLL version, there's no need to update this
You can/should use RecaptchaControlMvc.GenerateCaptcha() method in your View instead of writing your own (it will use the new URL)

Categories