stop unauthorized file download in asp.net - c#

I have a login.aspx page with custom textbox for username and password i.e. no loginview
after supplying correct username and pwd i assign a sessionid which is used to visit other pages on website.
Now to download a file (1234) i redierct the user to ~/download.aspx?fileid=1234, on this page i check the session id and send the user to file url i.e. ~/file/1234.pdf.
if some one dirctly enters file url, then i am unable to stop him.
plase guide me on how to do this...
P.S. : i have read about authentication rule in web.config file but dont know how to mark user as authenticated ones he supplies correct username and password at login. (i am only checking username and pwd from database and redirecting to home page)

Your authentication strategy is fairly weak. You should be bounding areas of your site (namely the files directory in this instance) with roles and assigning users to them.
However, to get around the more immediate problem, simply disable the outside world from getting to the files directory and when they hit ~/download.aspx?fileid=1234 just serve them the file. You can find instructions for this here: How to properly serve a PDF file

Take a look at this - http://support.microsoft.com/kb/301240
Look for point 4 in that article under - "Code the Event Handler So That It Validates the User Credentials", it explains you how to set authentication cookie after validating user
Code to look at:
FormsAuthenticationTicket tkt;
string cookiestr;
HttpCookie ck;
tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
DateTime.Now.AddMinutes(30), chkPersistCookie.Checked, "your custom data");
cookiestr = FormsAuthentication.Encrypt(tkt);
ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
if (chkPersistCookie.Checked)
ck.Expires=tkt.Expiration;
ck.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(ck);
What you can do is:
1. Enable form authentication in web.config
2. deny anonymous access to downloads folder
3. When user authenticates, set authentication cookie and redirect user to download folder
4. download folder now can only be accessed by logged in user and id

Below is the code I use in my projects
void ServeFile(string fname, bool forceDownload)
{
if(UserHasPermission(fname))
{
DownloadFile(fname,forceDownload);
}
else
{
ShowMessage("You have no permission");
}
}
private void DownloadFile( string fname, bool forceDownload )
{
string path = MapPath( fname );
string name = Path.GetFileName( path );
string ext = Path.GetExtension( path );
string type = "";
// set known types based on file extension
if ( ext != null )
{
switch( ext.ToLower() )
{
case ".htm":
case ".html":
type = "text/HTML";
break;
case ".txt":
type = "text/plain";
break;
case ".doc":
case ".rtf":
type = "Application/msword";
break;
case ".pdf":
type = "Application/pdf";
break;
}
}
if ( forceDownload )
{
Response.AppendHeader( "content-disposition",
"attachment; filename=" + name );
}
if ( type != "" )
Response.ContentType = type;
Response.WriteFile( path );
Response.End();
}

Related

Posting to Facebook only available to admin c#

I can successfully post to Facebook, however the posts are not public that everyone can see, only the primary page admin. Even after manually going through each post and "approving" them they are still not publicly available. I posted the question to Facebook and got a thank you for posting a question but no answer.
I created a Facebook app then using Facebook Graph API I got some access tokens for the app and made the access token permanent.
I can post using the Facebook SDK for .Net but again on the primary page admin can see the posts and nothing will make them visible.
Here is the access token info:
App ID 435958876564133 : RROADSus
Profile ID 830833833664593 : RROADSus
User ID
596954487156779 : Janel Xxxxx
User last installed this app via API N/A
Issued 1487528725 (about a month ago)
Expires Never
Valid True
Origin Web
Scopes manage_pages, publish_pages, pages_manage_cta, publish_actions, public_profile
Here is the code in the class to post to Facebook:
public static void postGotRV_FB(string Msg, string Picture, string Link, string Caption, string Desc)
{
string fb_Token = ConfigurationManager.AppSettings["fb:PermToken"];
FacebookClient client = new FacebookClient(fb_Token);
dynamic messagePost = new ExpandoObject();
messagePost.access_token = fb_Token;
messagePost.message = Msg.ToString().Trim();
if (string.IsNullOrEmpty(Picture) == false)
{
Picture = Picture.Replace("../", "http://www.RROADS.us/");
messagePost.source = Picture;
}
if (string.IsNullOrEmpty(Link) == false)
messagePost.link = Link.ToString().Trim();
if (string.IsNullOrEmpty(Caption) == false)
messagePost.caption = Caption.ToString().Trim();
if (string.IsNullOrEmpty(Desc) == false)
messagePost.description = Desc;
var result = client.Post("/830833833664593/feed", messagePost);
}
Here is the code I am calling to test the function off a button keypress:
protected void Unnamed1_Click(object sender, EventArgs e)
{
//string image = "Got-RV.png";
string image = "../Images/RROADS.png";
string Msg = "Hello From RROADS.us";
string Link = "http://www.RROADS.us";
string Caption = "Image Caption";
string Desc = "This is my test Description";
SocialMedia.postGotRV_FB(Msg, image, Link, Caption, Desc);
}
The post appears when you view the page as admin :
Hello From RROADS.us
<< IMAGE IS HERE >>
The Heart of Your Adventure
This is my test Description
IMAGE CAPTION
But when you view the page as anyone else this post does not appear.
What am I missing?
Thank you in advance!

ASP.NET error getting user details from Active Directory

I am trying to build a registration section for a website (internal to my dept). Now to get new users registered, I built a form where user enters his employee id i.e. AD account name and then clicks a button to fetch his details. Which are later saved in database where registration requests are queued. Once those requests are approved by admin then only those users can use the application. Now the problem is that user is not logged in, so is it possible for non logged in user to fetch details from AD server. if it is then how.? Because when I tried the below listed code I am getting bad username or password error using FindOne function.
public string getProperties(string StaffCode, string property)
{
try
{
string result = "";
using (var de = new DirectoryEntry(_path))
using (var ds = new DirectorySearcher(de))
{
ds.Filter = string.Format("(sAMAccountName={0})", StaffCode);
ds.PropertiesToLoad.AddRange(new[] {
"sn", // last name
"givenName", // first name
"mail", // email
"telephoneNumber", // phone number
// etc - add other properties you need
});
var res = ds.FindOne();
if (res == null)
{
result = "noUserFound";
}
else
{
foreach (string propName in res.Properties.PropertyNames)
{
ResultPropertyValueCollection valueCollection = res.Properties[propName];
foreach (Object propertyValue in valueCollection)
{
if (propName == property)
{
result = propertyValue.ToString();
}
}
}
}
}
return result;
}
catch (Exception ex)
{
return "someErrorOccurred";
}
Please help me in overcoming this issue.
Thanks in advance
My guess is that the identity of the application pool you run this code under doesn't have enough priviledges to query the AD without authentication.
Specifically, start with replacing this constructor
using ( var de = new DirectoryEntry( _path ) )
with the one that takes admin's username/password in an explicit way
using ( var de = new DirectoryEntry( _path, username, password ) )
and make sure the username has enough priviledges to query the catalog.
If this works, you could possibly try to go back to the original version but you'd have to make sure the identity of the asp.net application pool has enough priviledges to query the AD but also, that the asp.net server is a part of the domain (if it is not, authentication without providing username/password in an explicit way will most likely not work).

Running a process with current credentials

I am developing an Umbraco intranet site where I call wkhtmltopdf.exe to create some pdfs. Those pdfs are using a main page for the content and two additional pages for header and footer. Things worked pretty fine as long as I had the site without authentication. We want to use our Active Directory accounts to login to the site and thus I have enabled windows authentication. The routine for running this is to click a button that process the page and either shows the pdf on the browser or downloads it. In any case it is the same process. In visual studio when running with debugging when it comes to the first part of the code (var p = ...) it throws an exception "Message = "No process is associated with this object." because it fails to authenticate. I can see that when I pause the code just after its execution and using the visual studio inspector. The method runs to the end but because of the error I mentioned before it produces a blank pdf. If I hardcode username and password then it works fine.
Site is running in my local dev enviroment in iis express. Since Windows Authentication is enabled when I browse to the site the first time I have to login. Wkhtmltopdf.exe is located in the local drive - it is not on the website. The initial setup is based on the method described here http://icanmakethiswork.blogspot.se/2012/04/making-pdfs-from-html-in-c-using.html Only users that are part of our Active Directory domain will have access to the website but since we use the same accounts to login to windows then windows authentication will do the trick :)
public static void HtmlToPdf(string outputFilename, string[] urls,
string[] options = null,
bool streamPdf = false,
string pdfHtmlToPdfExePath = "C:\\Program Files (x86)\\wkhtmltopdf\\bin\\wkhtmltopdf.exe")
{
string urlsSeparatedBySpaces = string.Empty;
try
{
//Determine inputs
if ((urls == null) || (urls.Length == 0))
{
throw new Exception("No input URLs provided for HtmlToPdf");
}
urlsSeparatedBySpaces = String.Join(" ", urls); //Concatenate URLs
var p = new System.Diagnostics.Process()
{
StartInfo =
{
FileName = pdfHtmlToPdfExePath,
Arguments = ((options == null) ? "" : String.Join(" ", options)) + " " + urlsSeparatedBySpaces + " -",
UseShellExecute = false, // needs to be false in order to redirect output
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none
WorkingDirectory = string.Empty
}
};
p.Start();
var output = p.StandardOutput.ReadToEnd();
byte[] buffer = p.StandardOutput.CurrentEncoding.GetBytes(output);
p.WaitForExit(60000);
p.Close();
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/pdf";
if (!streamPdf)
{
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename='" + outputFilename + "'");
}
HttpContext.Current.Response.BinaryWrite(buffer);
HttpContext.Current.Response.End();
}
catch (Exception exc)
{
throw new Exception("Problem generating PDF from HTML, URLs: " + urlsSeparatedBySpaces + ", outputFilename: " + outputFilename, exc);
}
}
I tested this with LoadUserProfile = true but that didnt't help also. After reading throughout various forum posts the only suggested solution that I saw was to force loging in the process by using UserName, Password etc. But that is bad since the user is already logged in and we could/should use something like CredentialCache.DefaultCredentials .
A workaround that I came too was to use DefaultCredentials in requests to save the htmls locally where I can access them without a problem and create the pdfs but even that is a painstaking process, since i need to create printable css and javascripts and download them etc etc. This is my last solution which I have implemented at 80% but seems nasty also. Here is another code sample how I grab the webpages.
var request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials;
var response = (HttpWebResponse)request.GetResponse();
var stream = response.GetResponseStream();
So to sum up. Wkhtmltopdf fails to authenticate itself so that it can grab the desired pages and turn them to pdf. Is there any neat way to make the process able to authenticate itself with current user's credentials that I am logged in to the site so that it can access the pages?
I Use Rotativa a wrapper for Wkhtmltopdf.
To get it working on iis, I created a separate user account with enough access to run Wkhtmltopdf.exe. Then Pass the User Name & Password to Wkhtmltopdf with the switches.
public virtual ActionResult PrintInvoice(int id) {
var invoice = db.Invoices.Single(i => i.InvoiceId == id);
var viewmodel = Mapper.Map<InvoiceViewModel>(invoice);
var reportName = string.Format(#"Invoice {0:I-000000}.pdf", invoice.InvoiceNo);
var switches = String.Format(#" --print-media-type --username {0} --password {1} ",
ConfigurationManager.AppSettings["PdfUserName"],
ConfigurationManager.AppSettings["PdfPassword"]);
ViewBag.isPDF = true;
return new ViewAsPdf("InvoiceDetails", viewmodel) {
FileName = reportName,
PageOrientation = Rotativa.Options.Orientation.Portrait,
PageSize = Rotativa.Options.Size.A4,
CustomSwitches = switches
};
}
It appears the pages running within Wkhtmltopdf.exe run with the current users credentials, but the Wkhtmltopdf.exe itself needs rights to execute on the server.
This works on iis when deployed. On Cassini in VS2012 it works for me with no credentials, but in vs2013 on iis express I'm still having trouble when it comes to picking up resources like css & images.
Same solution to run over SSL:
Rotativa and wkhtmltopdf no CSS or images on iis6 over HTTPS, but fine on HTTP
Turn on ASP.NET Impersonation and spawn wkhtmltopdf under the context of the impersonated user.
Note: turning on ASP.NET impersonation is very likely to decrease performance.

uploading to YouTube with ASP.NET C# - avoiding the "Google login" screen

I am creating an ASP.NET C# app that uploads videos to a YouTube Channel.
*I have already read through (to the best of my ability) the documentation at
The YouTube API Documentation
I have been able to successfully implement two examples of uploading a video to the YouTube channel using the sample code provided.
For example, using direct method (only the important code attached):
<!-- eja: import the google libraries -->
<%# Import Namespace="Google.GData.Client" %>
<%# Import Namespace="Google.GData.Extensions" %>
<%# Import Namespace="Google.GData.YouTube" %>
<%# Import Namespace="System.Net" %>
<!-- some more code -->
<%
// specify where to go to once authenticated
Uri targetUri = new Uri(Request.Url, "VideoManager.aspx");
// hide the link to authenticate for now.
GotoAuthSubLink.Visible = false;
// GotoAuthSubLink.Visible = true;
// look for a session var storing the auth token. if it's not empty
if (Session["token"] != null)
{
// go to the VideoManager link
Response.Redirect(targetUri.ToString());
}
else if (Request.QueryString["token"] != null)
{
// if we have the auth key in the URL, grab it from there instead
String token = Request.QueryString["token"];
// set the session equal to AuthSubUtil's calling the exchangeForSessionToken method
// returns the token and convert it to a string
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
Response.Redirect(targetUri.ToString(), true);
}
else
{
//no auth token, display the link and create the token by loading the google
// auth page
String authLink = AuthSubUtil.getRequestUrl(Request.Url.ToString(), "http://gdata.youtube.com", false, true);
GotoAuthSubLink.Text = "Login to your Google Account";
GotoAuthSubLink.Visible = true;
GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl(Request.Url.ToString(),"http://gdata.youtube.com",false,true);
}
<asp:HyperLink ID="GotoAuthSubLink" runat="server"/>
That's page one...it loads the google authentication screen. (see link to attached image ,it's safe, I just set up a new account here on stackOverflow and can't upload images yet).
Then it leads to a page with the upload mechanism...The uploading works I am not worried about that, but here is the snippet of code FYI.
// create an instance ot the YouTubeService class. passing the application name and my DEV KEY
YouTubeService service = new YouTubeService(authFactory.ApplicationName, **API_KEY**);
// retrieve the current session token as a string if any
authFactory.Token = HttpContext.Current.Session["token"] as string;
// incorporate the information into our service
service.RequestFactory = authFactory;
try
{
// a YouTubeEntry object is single entity within a videoFeed object. It generally contains info
// about the video. when uploading, we will assign the values that we received to the feed.
YouTubeEntry entry = new YouTubeEntry();
// aggregate all the initial descriptor information
entry.Media = new Google.GData.YouTube.MediaGroup();
entry.Media.Description = new MediaDescription(this.Description.Text);
entry.Media.Title = new MediaTitle(this.Title.Text);
entry.Media.Keywords = new MediaKeywords(this.Keyword.Text);
// process entry.Media.Categories to assign the category
MediaCategory category = new MediaCategory(this.Category.SelectedValue);
category.Attributes["scheme"] = YouTubeService.DefaultCategory;
entry.Media.Categories.Add(category);
// prepare the token used for uploading
FormUploadToken token = service.FormUpload(entry);
HttpContext.Current.Session["form_upload_url"] = token.Url;
HttpContext.Current.Session["form_upload_token"] = token.Token;
// construct the URL
string page = "http://" + Request.ServerVariables["SERVER_NAME"];
if (Request.ServerVariables["SERVER_PORT"] != "80")
{
page += ":" + Request.ServerVariables["SERVER_PORT"];
}
page += Request.ServerVariables["URL"];
HttpContext.Current.Session["form_upload_redirect"] = page;
Response.Redirect("UploadVideo.aspx");
The page UploadVideo.aspx is the actual upload form, and it works, so I am not concerned about that.
The alternate method is not the recommended method, as it's synchronous in nature, but it DOES avoid that login screen as it allows us to pass credentials to authenticate (it works as a web app)...again principal code attached below.
<%
GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory(ServiceNames.YouTube, "TesterApp");
// Response.Write("serviceNames.youtube=" + ServiceNames.YouTube + "<br />");
YouTubeRequestSettings s = new YouTubeRequestSettings(authFactory.ApplicationName, **your API KEY**,**Your email account as a username**,**your password**);
YouTubeRequest request = new YouTubeRequest(s);
Video newVideo = new Video();
newVideo.Title = "test at 4:40";
newVideo.Tags.Add(new MediaCategory("Games", YouTubeNameTable.CategorySchema));
newVideo.Keywords = "cars, funny";
newVideo.Description = "My description";
newVideo.YouTubeEntry.Private = false;
// newVideo.Tags.Add(new MediaCategory("mydevtag, anotherdevtag", YouTubeNameTable.DeveloperTagSchema));
// newVideo.YouTubeEntry.Location = new GeoRssWhere(37, -122);
// alternatively, you could just specify a descriptive string
newVideo.YouTubeEntry.setYouTubeExtension("location", "Somewhere,Someplace");
newVideo.YouTubeEntry.MediaSource = new MediaFileSource("C:\\IMG_1672.MOV",
"video/quicktime");
Video createdVideo = request.Upload(newVideo);
Response.Write("This will print out once the file is uploaded...indicates that the code is <i>synchronous</i>. The cursor spins around until done. go get a coffee then check the YouTube Channel");
%>
So basically the question that I am asking is - Is there a method that will upload a video to a YouTube Channel in ASP.NET C# code a) for a web application b) that I can pass credentials through the code to c) bypass the Google authentication screen seen above and d) without using OAuth and openID and a cert etc?
The App is for only a short campaign (November only) and I am happy to use the deprecated authSubUtil and a dev key and do not need to worry about oAuth 2.x or open ID (since authsubutil will deprecate in 2015 anyway).
Any Help is appreciated.
thanks
Edward
You would be best placed to use the ClientLogin authentication, where you can store a users username & password for their account and then use DirectUpload.
Direct Upload: https://developers.google.com/youtube/2.0/developers_guide_dotnet#Direct_Upload
ClientLogin: https://developers.google.com/youtube/2.0/developers_guide_protocol_clientlogin#ClientLogin_Authentication
Note client login is being deprecated, and they want you to use OAuth, however if you do it quickly you should be okay!

What should I fetch from gmail DotNetOpenAuth?

I want to use DotNetOpenAuth in my website for authentication + authorization (gmail).
However, I would like to ask: What should I persist?
I thought:
In the DB: for each user save a Guid and his gmail (fetched)
In formAuthentication cookie the Guid I have assigned to that user.
Any other suggestions?
public bool Login()
{
IAuthenticationResponse authResponse = GoogleConsumerHandler.RelyingParty.GetResponse();
if (authResponse != null)
{
HandleAuthResponse(authResponse);
}
else
{
HandleAuthNullResponse(authResponse);
}
return false;
}
#region private methods
private void HandleAuthResponse(IAuthenticationResponse authResponse)
{
switch (authResponse.Status)
{
case AuthenticationStatus.Authenticated:
State.FetchResponse = authResponse.GetExtension<FetchResponse>();
var consumer = new WebConsumer(GoogleConsumerHandler.ServiceDescription, mConsumerTokenManager);
AuthorizedTokenResponse accessToken = consumer.ProcessUserAuthorization(authResponse);
if (accessToken != null)
{
var email = authResponse.ClaimedIdentifier;
//existing or new
Guid userId = mCRMService.GetUserId(email, accessToken.AccessToken);
State.GoogleAccessToken = accessToken.AccessToken;
FormsAuthentication.SetAuthCookie(userId.ToString(), false);
//authenticat and authorized
//Response.Redirect("~/Browser.htm");
}
else
{
//authenticated and not authorized
//MultiView1.SetActiveView(AuthorizationDenied);
}
break;
case AuthenticationStatus.Canceled:
break;
case AuthenticationStatus.Failed:
break;
default:
//not authenticated
//this.MultiView1.SetActiveView(this.AuthenticationFailed);
break;
}
}
private void HandleAuthNullResponse(IAuthenticationResponse authResponse)
{
// Google requires that the realm and consumer key be equal,
// so we constrain the realm to match the realm in the web.config file.
// This does mean that the return_to URL must also fall under the key,
// which means this sample will only work on a public web site
// that is properly registered with Google.
// We will customize the realm to use http or https based on what the
// return_to URL will be (which will be this page).
var consumer = new WebConsumer(GoogleConsumerHandler.ServiceDescription, mConsumerTokenManager);
//Realm realm = "http://localhost:8976/";
Realm realm = System.Web.HttpContext.Current.Request.Url.Scheme + Uri.SchemeDelimiter + consumer.ConsumerKey + "/";
IAuthenticationRequest authReq = GoogleConsumerHandler.RelyingParty.CreateRequest(GoogleConsumerHandler.GoogleOPIdentifier, realm);
// Prepare the OAuth extension
string scope = GoogleConsumerHandler.GetScopeUri(GoogleConsumerHandler.Applications.Gmail);
consumer.AttachAuthorizationRequest(authReq, scope);
// We also want the user's email address
var fetch = new FetchRequest();
fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
authReq.AddExtension(fetch);
authReq.RedirectToProvider();
}
For authentication purposes you should store the OpenID ClaimedIdentifier you get back in the IAuthenticationResponse object. That serves as the "primary key" for your users so you can recognize them when they return. I suggest you use the claimed_id as the FormsAuthentication username instead of a random GUID as well. Also storing the email address you collect is fine, but it's inadvisable to use that as the means to recognize a returning user.
Remember that you can't log in "gmail users". You can log in OpenID users, that may use any Provider. You can limit that to "Google" users by filtering on the IAuthenticationResponse.Provider.Uri for the Google OP Endpoint, but even then you're not guaranteed that those accounts use Gmail (their email address might be foo#bar.com anyway).
Finally, if all you need is their authentication and email address (whatever email that is) you can do so using the OpenID AX extension (built into DNOA) and you don't need "authorization", which might greatly simplify your code.

Categories

Resources