I have a PHP page running on IIS8.
Authentication is done through ADFS.
I would like to access the values of some of the claims in the user's SAML token from the PHP page, but I think those values are not stored anyway.
I tried creating a custom HttpModule to pass values to the PHP page:
using Microsoft.IdentityModel.Claims;
using System;
using System.Threading;
using System.Web;
public class TestModule : IHttpModule {
public void Init(HttpApplication context) {
context.AuthenticateRequest += Context_AuthenticateRequest;
}
private void Context_AuthenticateRequest(object sender, EventArgs e) {
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
IClaimsPrincipal principal = Thread.CurrentPrincipal as IClaimsPrincipal;
if (principal == null || principal.Identities == null || principal.Identities.Count == 0) {
context.Response.Write("TestModule: cannot get claims.<br/>");
return;
}
IClaimsIdentity identity = principal.Identities[0];
foreach (Claim claim in identity.Claims) {
if (claim.ClaimType == "http://schemas.xmlsoap.org/claims/DisplayName") {
context.Response.Write("TestModule: setting USER_DISPLAY_NAME to " + claim.Value + "<br/>");
Environment.SetEnvironmentVariable("USER_DISPLAY_NAME", claim.Value);
}
}
}
public void Dispose() {
}
}
This is executed, and the variable is set to the good value.
In the PHP page I have this:
<?php
echo getenv('USER_DISPLAY_NAME');
?>
But nothing is displayed.
Is it possible to pass a variable to a PHP page with a custom module?
Is there another more standard way to get ADFS claims values from a PHP page in IIS?
Related
I tried to prevent user for changing the "ASP.NET_SessionId"
I tried this code:
Response.Cookies["ASP.NET_SessionId"].Value = GenerateHashKey();
But my session (Session["userId"]) was removed when I tried to set the cookie
Here is some code that I tried without success:
protected void Application_BeginRequest(object sender, EventArgs e)
{
//Check If it is a new session or not , if not then do the further checks
if (Request.Cookies["ASP.NET_SessionId"] != null && Request.Cookies["ASP.NET_SessionId"].Value != null)
{
string newSessionID = Request.Cookies["ASP.NET_SessionID"].Value;
//Check the valid length of your Generated Session ID
if (newSessionID.Length <= 24)
{
//Log the attack details here
Response.StatusCode = 401;
}
//Genrate Hash key for this User,Browser and machine and match with the Entered NewSessionID
if (GenerateHashKey() != newSessionID.Substring(24))
{
//Log the attack details here
Response.StatusCode = 401;
//throw new HttpException("401");
}
//Use the default one so application will work as usual//ASP.NET_SessionId
Request.Cookies["ASP.NET_SessionId"].Value = Request.Cookies["ASP.NET_SessionId"].Value.Substring(0, 24);
}
}
private string GenerateHashKey()
{
StringBuilder myStr = new StringBuilder();
myStr.Append(Request.Browser.Browser);
myStr.Append(Request.Browser.Platform);
myStr.Append(Request.Browser.MajorVersion);
myStr.Append(Request.Browser.MinorVersion);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hashdata = sha.ComputeHash(Encoding.UTF8.GetBytes(myStr.ToString()));
return Convert.ToBase64String(hashdata);
}
protected void Application_EndRequest(object sender, EventArgs e)
{
//Pass the custom Session ID to the browser.
if (Response.Cookies["ASP.NET_SessionId"] != null)
{
Response.Cookies["ASP.NET_SessionId"].Value = Request.Cookies["ASP.NET_SessionId"].Value + GenerateHashKey();
}
}
How to prevent the user for set session
Looks like you are trying to secure your session value from tampering? If you set the value yourself, you override the session identifier and destroy the purpose of the asp session cookie.
ASP.Net_SessionId is a cookie which is used to identify the users session on the server. The session being an area on the server which can be used to store data in between http requests.
If you are trying to solve the session fixation problem, which is the only vulnerability of asp session cookie, then you need to introduce a new cookie like this: https://medium.com/#grep_security/session-fixation-broken-authentication-and-session-management-c37ce0111bf5
I'm using the code below from this post to try and create a custom http module :
public class BasicAuthenticationModule: IHttpModule
{
public void Init(HttpApplication application)
{
application.AuthenticateRequest += new EventHandler(Do_Authentication);
}
private void Do_Authentication(object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
string header = request.Headers["HTTP_AUTHORIZATION"];
if(header != null && header.StartsWith("Basic "))
{
// Header is good, let's check username and password
string username = DecodeFromHeader(header, "username");
string password = DecodeFromHeader(header, password);
if(Validate(username, password)
{
// Create a custom IPrincipal object to carry the user's identity
HttpContext.Current.User = new BasicPrincipal(username);
}
else
{
Protect();
}
}
else
{
Protect();
}
}
private void Protect()
{
response.StatusCode = 401;
response.Headers.Add("WWW-Authenticate", "Basic realm=\"Test\"");
response.Write("You must authenticate");
response.End();
}
private void DecodeFromHeader()
{
// Figure this out based on spec
// It's basically base 64 decode and split on the :
throw new NotImplementedException();
}
private bool Validate(string username, string password)
{
return (username == "foo" && pasword == "bar");
}
public void Dispose() {}
public class BasicPrincipal : IPrincipal
{
// Implement simple class to hold the user's identity
}
}
The code works ok at making the 401 error be returned by the server and the login dialog pop up but when the correct login details are entered the login dialog does not go away.
When debugging the code nothing happens when the Ok button on the dialog is clicked, the event isn't triggered and the user details aren't validated, I can't figure out why this isn't working.
Any help or ideas would be great, thanks.
On Microsoft's asp.net website, there is a good example on how to do custom authentication. Ignore the fact that it says it's about WebAPI. The code uses a IHttpModule, so it works with WebForms, IHttpHandler, asmx, WCF, and anything else that runs in IIS. Copying and pasting the code at the end of that page into a new project works for me. Although, I don't recommend setting the thread's CurrentPrincipal to the authenticated user, like the sample does. I prefer to just use the current context's User property.
If your breakpoint in the module isn't getting hit, then it's almost certainly because the http module wasn't registered correctly. The asp.net page I linked above shows how to register the module in your web.config file, so you should start there. You should be able to use Visual Studio's intellisense auto-complete to complete your class name, which helps make sure you typed it right (although there is a chance that Resharper is doing it on my machine, but I think it's just plain Visual Studio).
I am using uploadify to upload files, they automatically post to the handler. I then modify the session in the handler that I have setup as a static property in a common class of the website. I then try to access that same session in the aspx page, and the value is null. I have a feeling this is because of cookies, but there needs to be a way to work around this without exposing the sessionid in the url.
ASHX:
public class Upload : IHttpHandler, IReadOnlySessionState, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
...
CMSSession.Current.UploadedFiles.Add(fileName);
}
}
Session Class:
public class CMSSession
{
public static CMSSession Current
{
get
{
CMSSession session = (CMSSession)HttpContext.Current.Session["__CMSSession__"];
if (session == null)
{
session = new CMSSession();
HttpContext.Current.Session["__CMSSession__"] = session;
}
return session;
}
}
public List<string> UploadedFiles { get; set; }
}
ASPX:
if (CMSSession.Current.UploadedFiles != null)
{
...
}
else
{
IT'S ALWAYS NULL
}
Web.Config:
<sessionState mode="InProc" cookieless="false" /> - causes session to always null in aspx when modified in ashx
<sessionState mode="InProc" cookieless="true" /> - session value is not null, but sessionid is exposed in the url
How do I access & modify the current session within the ASHX file WITHOUT changing cookieless to true and then access the session from the ASPX page?
I have tried using HttpContext and using the context passed into the ASHX...nothing works.
same as this question, but there has to be a more secure way: session set in ashx and get that session on aspx
Any ideas?
I found the answer: When the handler is being called from FLASH (like swfupload or uploadify) it does not pass the current sessionid to the handler. The handler then creates a NEW session. To fix this, do the following:
Your UI: JavaScript:
$(Selector).uploadify({
swf: 'uploadify.swf',
uploader: 'Upload.ashx?ASPSESSID=<%=Session.SessionID%>'
});
Add to: Global.asax:
void Application_BeginRequest(object sender, EventArgs e)
{
try
{
string session_param_name = "ASPSESSID";
string session_cookie_name = "ASP.NET_SESSIONID";
string session_value = Request.Form[session_param_name] ?? Request.QueryString[session_param_name];
if (session_value != null) { UpdateCookie(session_cookie_name, session_value); }
}
catch (Exception) { }
}
void UpdateCookie(string cookie_name, string cookie_value)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name);
if (cookie == null)
{
HttpCookie cookie1 = new HttpCookie(cookie_name, cookie_value);
Response.Cookies.Add(cookie1);
}
else
{
cookie.Value = cookie_value;
HttpContext.Current.Request.Cookies.Set(cookie);
}
}
Taken & simplified for uploadify from:
http://snipplr.com/view/15180/
You may need to use an authid if using formsauthentication:
&AUTHID=<%= Request.Cookies[FormsAuthentication.FormsCookieName] == null ? "" : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>
append that to the uploader parameter in the jQuery.
Then add the following to the global:
try
{
string auth_param_name = "AUTHID";
string auth_cookie_name = FormsAuthentication.FormsCookieName;
string auth_value = Request.Form[auth_param_name] ?? Request.QueryString[auth_param_name];
if (auth_value != null) { UpdateCookie(auth_cookie_name, auth_value); }
}
catch (Exception) { }
You can now access the same session from the handler (even using the static session object I used above in the question) in IE, Chrome, FF, ect.
Context.Session is null.. because connection to HttpHandler has another Context.Session
(debug and try: Context.Session.SessionId in where is the fileInput is different from Context.Session.SessionId in Upload.ashx)!
I suggest a workaround: pass a reference to the elements you need in the second session ( in my sample i pass the original SessionId using sessionId variable)
....
var sessionId = "<%=Context.Session.SessionID%>";
var theString = "other param,if needed";
$(document).ready(function () {
$('#fileInput').uploadify({
'uploader': '<%=ResolveUrl("~/uploadify/uploadify.swf")%>',
'script': '<%=ResolveUrl("~/Upload.ashx")%>',
'scriptData': { 'sessionId': sessionId, 'foo': theString },
'cancelImg': '<%=ResolveUrl("~/uploadify/cancel.png")%>',
....
and use this items in .ashx file.
public void ProcessRequest(HttpContext context)
{
try
{
HttpPostedFile file = context.Request.Files["Filedata"];
string sessionId = context.Request["sessionId"].ToString();
....
If you need to share complex elements use Context.Application instead of Context.Session, using original SessionID: Context.Application["SharedElement"+SessionID]
I have some proof concept code for a HTTP module. The code checks to see if a cookie exists, if so it retrieves a value, if the cookie does not exist it creates it and sets the value.
Once this is done I write to the screen to see what action has been taken (all nice and simple). So on the first request the cookie is created; subsequent requests retrieve the value from the cookie.
When I test this in a normal asp.net web site everything works correctly – yay! However as soon as I transfer it to SharePoint something weird happens, the cookie is never saved - that is the code always branches into creating the cookie and never takes the branch to retrieve the value - regardless of page refreshes or secondary requests.
Heres the code...
public class SwithcMasterPage : IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}
public void Init(HttpApplication context)
{
// register handler
context.PreRequestHandlerExecute += new EventHandler(PreRequestHandlerExecute);
}
void PreRequestHandlerExecute(object sender, EventArgs e)
{
string outputText = string.Empty;
HttpCookie cookie = null;
string cookieName = "MPSetting";
cookie = HttpContext.Current.Request.Cookies[cookieName];
if (cookie == null)
{
// cookie doesn't exist, create
HttpCookie ck = new HttpCookie(cookieName);
ck.Value = GetCorrectMasterPage();
ck.Expires = DateTime.Now.AddMinutes(5);
HttpContext.Current.Response.Cookies.Add(ck);
outputText = "storing master page setting in cookie.";
}
else
{
// get the master page from cookie
outputText = "retrieving master page setting from cookie.";
}
HttpContext.Current.Response.Write(outputText + "<br/>");
}
private string GetCorrectMasterPage()
{
// logic goes here to get the correct master page
return "/_catalogs/masterpage/BlackBand.master";
}
This turned out to be the authentication of the web app. To work correctly you must use a FQDM that has been configured for Forms Authentication.
You can use Fiddler or FireBug (on FireFox) to inspect response to see if your cookie is being sent. If not then perhaps you can try your logic in PostRequestHandlerExecute. This is assuming that Sharepoint or some other piece of code is tinkering with response cookies. This way, you can be the last one adding the cookie.
I have built a shopping cart that uses Session State to keep the shopping cart data while the user is browsing the store.
I have an issue where if I leave the browser window open for a long time on step1 of the shopping cart, then press "go to step 2", my actions throw an error because the step2 action assumes the session hasn't expired and the ShopCart object is in the correct state.
I would like this scenario to be nicer for my users, but I think i need to somehow detect if the session has expired so that on next request I can throw them to Step1.
I found the following code that claims to to solve the problem, but it doesn't work for me.
The IsNewSession condition is true but the condition
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0)) {
// handle expired session
}
always returns false and it never handles the invalid session. I'm confused.
Is this possible in ASP.NET (and MVC)?
Way 1
Put this code in the Init / Load event of Page 2...
if (Context.Session != null)
{
if (Context.Session.IsNewSession)
{
string sCookieHeader = Request.Headers["Cookie"];
if ((null != sCookieHeader) && (sCookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
{
if (Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
}
Response.Redirect("Error Page");
}
}
}
Way 2
Alternative you can check whether the Session object exists before proceeding to work with it in Page 2, like this:
if (Session["Key"] != null)
{
Object O1 = (Object) Session["Key"];
}
else
{
Response.Redirect("ErrorPage.aspx");
}
The King 's answer does not work for me. I have added FormsAuthentication.SignOut() in OnActionExcuting(). The Response.Redirect will not work!
if (Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
}
This is my complete method
public class SessionExpireFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// check if session is supported
if (ctx.Session != null)
{
// check if a new session id was generated
if (ctx.Session.IsNewSession)
{
// If it says it is a new session, but an existing cookie exists, then it must
// have timed out
string sessionCookie = ctx.Request.Headers["Cookie"];
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
{
string redirectOnSuccess = filterContext.HttpContext.Request.Url.PathAndQuery;
string redirectUrl = string.Format("?ReturnUrl={0}", redirectOnSuccess);
string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
if (ctx.Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
}
RedirectResult rr = new RedirectResult(loginUrl);
filterContext.Result = rr;
//ctx.Response.Redirect("~/Home/Logon");
}
}
}
base.OnActionExecuting(filterContext);
}
}
You need to create the Session_OnEnd method In Global.asax.cs file in your project.
this is my code and I am able to Detecting Session expiry on ASP.NET MVC
protected void Session_OnEnd(object sender, EventArgs e)
{
int userid = 0;
userid = Convert.ToInt32(Session["UserID"]);
if (userid != 0)
{
var userActivity = DependencyResolver.Current.GetService<IUserRepo>();
var responce = userActivity.LogOutUsers(userid);
if (responce == true)
{
Session.Clear();
Session.Abandon();
}
}
}
more