I'm renaming the cookie and made it to target to a different path, rather than targeting to a default path "/".
Below is the web.config settings:
<sessionState sessionIDManagerType="MyNamespace.MySessionIDManager" cookieName="AppCookie"/>
Below is the backend class used to create the cookie:
public class MySessionIDManager : SessionIDManager, ISessionIDManager
{
void ISessionIDManager.SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
{
base.SaveSessionID(context, id, out redirected, out cookieAdded);
if (cookieAdded)
{
var name = "AppCookie";
var cookie = context.Response.Cookies[name];
cookie.Path = "/Forms";
}
}
}
This fix is working fine for me locally. The cookie is successfully pointing to the given path i.e "/Forms".
But when I deploy my application to IIS, I'm not able to login to the application.
It is not throwing any error, but not allowing me to login to the web application.
If I use to below web.config settings, it is working fine.
<sessionState mode="InProc" timeout="30" cookieName="AppCookie" />
Please let me know what issue it is causing in the IIS.
Any input is much appreciated.
Thank you all in advance.
Thanks and Regards,
Dada.
please try to change the URL from http://www.website/login/ to http://www.website/forms/login/ and then you can see the cookie will send in the request header, and you will auto login.
This is caused by you change the cookie URL to /forms, it means that only the http URL has /forms string will send the session cookie which has created with the aspnet_sessionID.
If you don't change the cookie URL, default path '/' means the cookie can be shared.
You can see this link: https://learn.microsoft.com/en-us/dotnet/api/system.web.httpcookie.path?view=netframework-4.8
I fixed this issue with the below piece of code;
public class CookieManager : SessionIDManager, ISessionIDManager
{
void ISessionIDManager.SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
{
base.SaveSessionID(context, id, out redirected, out cookieAdded);
if (cookieAdded)
{
SessionStateSection sessionStateSection = (System.Web.Configuration.SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState");
var cookie = context.Response.Cookies[sessionStateSection.CookieName];
cookie.Path = context.Request.ApplicationPath;
}
}
}
And update the web.config as follows;
<sessionState sessionIDManagerType="ANJU.Reports.WebUI.Library.CookieManager" timeout="30" cookieName="CookieName"/>
Now when I host my application on the IIS, it'll fetch the directory where I have my build.
All my cookies will point to the root directory of the build.
Related
We are implementing cross site scripting protection in MVC5 by using the built in ValidateAntiForgeryToken attribute and #Html.AntiForgeryToken() helper.
This all works. However, our app runs in a frame that is in a different domain. So, we need to set the cookie to SameSite=none (as we have done with session and auth cookies).
I can't find a way to configure the cookie to include this setting.
I have tried to create an OWIN middle ware to check the cookies on the way out and update it, but the cookie collection in the response in the OWIN context is read only.
How can I get this setting on the cookie?
Adding this to global.asax.cs to set the token to Same Site = none should fix it
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
// This code will mark the __RequestVerificationToken cookie SameSite=None
if (Request.Cookies.Count > 0)
{
foreach (string s in Request.Cookies.AllKeys)
{
if (s.ToLower() == "__requestverificationtoken")
{
HttpCookie c = Request.Cookies[s];
c.SameSite = System.Web.SameSiteMode.None;
Response.Cookies.Set(c);
}
}
}
}
I have an ASP.NET 6 MVC application running in Azure. I have a controller with an action like
[HttpDelete]
[Route("{image_url}")]
public async Task<IActionResult> RemoveImageUrl([FromRoute(Name = "image_url")] String imageUrlString)
I then call it like
api/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Full-Size.png"
This application works fine when self hosting with Kestrel, but as soon as I deploy to Azure I get 500 errors. I have debugged as much as I can and after a lot of Googling and poking it appears that IIS is attempting to helpfully URL Decode the request before forwarding it on to ASP.NET to handle. The problem, of course, is that even if I can convince IIS to accept the request with
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
</system.webServer>
<system.web>
<httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters="" relaxedUrlToFileSystemMapping="true"/>
<pages validateRequest="false" />
</system.web>
It still decodes the URL and passes the decoded URL on to ASP.NET which doesn't find a matching route.
What can I do to tell IIS to stop trying to be helpful here and just pass along whatever URL it gets, without doing any sort of pre-validation or rewriting along the way? Note: this is an Azure Web App, so I don't have direct access to IIS settings.
You could just update your route definition so it matches a decoded image url parameter.
As per the documentation, when defining route templates:
You can use the * character as a prefix to a route value name to bind
to the rest of the URI. For example, blog/{*slug} would match any URI
that started with /blog/ and had any value following it (which would
be assigned to the slug route value).
So you could create an action matching the route [Route("{*image_url}")]:
[Route("{*image_url}")]
public IActionResult RemoveImageUrl([FromRoute(Name = "image_url")]String imageUrlString)
{
return Json(new { ReceivedImage = imageUrlString });
}
The only problem I have seen is that the protocol part is decoded as http:/ with a single /. You have a couple of options:
You could manually fix it in the controller. Even better, you could create a model binder and a parameter convention to do that automatically:
[HttpDelete]
[Route("{*image_url}")]
public IActionResult RemoveImageUrl([FullUrlFromEncodedRouteParam(Name = "image_url")] String imageUrlString)
{
return Json(new { ReceivedImage = imageUrlString });
}
public class FullUrlFromUrlEncodedPathSegmentModelBinder : IModelBinder
{
//Matches a url that starts with protocol string and is followed by exactly ":/" instead of "://"
private static Regex incorrectProtocolRegex = new Regex(#"^([a-z][\w-]+:)\/{1}(?!\/)");
//A url path included as a url encoded path segment like http://localhost:39216/image2/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Web.png
//will be decoded by IIS as https:/repocreator.zoltu.io/images/Zoltu-Logo-Web.png, note the single '/' after the protocol
//This model binder will fix it replacing "http:/" with "http://"
public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ValueProvider.GetValue(bindingContext.ModelName) == null)
return Task.FromResult(ModelBindingResult.NoResult);
var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue as string;
var fixedVal = incorrectProtocolRegex.Replace(val, #"$1//");
return Task.FromResult(ModelBindingResult.Success(bindingContext.ModelName, fixedVal));
}
}
public class FullUrlFromEncodedRouteParamAttribute : Attribute, IParameterModelConvention
{
public string Name { get; set; }
public void Apply(ParameterModel parameter)
{
parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
parameter.BindingInfo.BinderModelName = Name;
parameter.BindingInfo.BindingSource = BindingSource.Path;
parameter.BindingInfo.BinderType = typeof(FullUrlFromUrlEncodedPathSegmentModelBinder);
}
}
A better approach might be updating your api so you don't even use the protocol part in the image key. That will let you add the proper protocol to the full image url when you need to render it, depending on whether it needs http or https (Even the host could be omitted from the urls). You wouldn't even need to worry about url encoding the image path on your client side, you could just invoke it like http://localhost:39216/api/repocreator.zoltu.io/images/Zoltu-Logo-Full-Size.png.
IMHO I would prefer the second approach. If you really need the full url encoded in the route, then at least you have a way of implementing it in a clean way outside the controller.
Note: If you want to keep the protocol part in the image url, it looks like the static files middleware does not like them so it has to be added after MVC in Startup.configure, otherwise it will throw errors.
I have a Service Stack service hosted within a SharePoint 2013 site. When attempting to make a cross domain request to one of the services, a preflight OPTIONS request is made, as expected.
The problem is that the response always comes back as 401 Unauthorized, due to the fact that authentication info is not sent across with the request. I have tried putting some request filters via servicestack to try and bypass the authentication, but these filters are not firing - it seems like something prior to service stack is sending the response.
Is there any way of specifying that OPTIONS requests to the sharepoint site do not need to be authenticated? If not, does anyone have a workaround for this scenario?
I tried 'fooling' the browser in to not sending a preflight request by changing the data type from application/json to text/plain in my ajax request, but then the data I send is not being deserialised in to the correct RequestDTO for the service calls on the server side.
Any help would be appreciated.
We ended up having to write our own HTTP module in order to support the options request. We basically add a key specifying which domains to allow the CORS requests from (can support more than one) and then have this HTTP module registered:
public class ECSPreFlightModule : IHttpModule
{
/// <summary>
/// You will need to configure this module in the Web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
public void Dispose()
{
//clean-up code here.
}
private const string OptionsHeader = "OPTIONS";
private const string OriginHeader = "ORIGIN";
private const string AccessAllowOrigin = "Access-Control-Allow-Origin";
private string AllowedOriginUrlsArray
{
get
{
return GetWebConfigValue("CORSAllowedOriginUrls");
}
}
private string GetWebConfigValue(string key)
{
var configuration = WebConfigurationManager.OpenWebConfiguration("~");
object o = configuration.GetSection("system.web/httpModules");
var section = o as HttpModulesSection;
return section.CurrentConfiguration.AppSettings.Settings[key].Value;
}
public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += (sender, e) =>
{
var splitUrls = AllowedOriginUrlsArray.Split('|');
var response = context.Response;
var originHeader = context.Request.Headers.Get(OriginHeader);
if (!String.IsNullOrEmpty(originHeader) && splitUrls.Length > 0)
{
foreach (var url in splitUrls)
{
var urlLower = url.ToLower();
var originHeaderLower = originHeader.ToLower();
// if the method being requested is an OPTIONS request and the url is the url specified in the web.config then return an OK response.
if (context.Request.HttpMethod.ToLowerInvariant() == OptionsHeader.ToLowerInvariant() &&
(urlLower == originHeaderLower))
{
response.StatusCode = (int)HttpStatusCode.OK;
}
// If the originating header url is equal to the url specified in the web.config then grant the access control
if (originHeaderLower == urlLower)
{
response.AddHeader(AccessAllowOrigin, originHeader);
break;
}
}
}
};
}
}
}
The above module was wrapped in a sharepoint feature that, when activated, made the appropriate changes to the web.config, namely registering the module and adding the following keys:
<add name='Access-Control-Allow-Credentials' value='true' />
<add name='Access-Control-Allow-Headers' value='Authorization, X-Requested-With, Content-Type, Origin, Accept, X-RequestDigest' />
<add name='Access-Control-Allow-Methods' value='GET,POST,OPTIONS,PUT, DELETE' />
Can any one help us to run the URL through java code :
we are trying to upload a file from our local drive to Gmail Drive.
Steps Followed
Generated the URL with the help of Google Developer(API)
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE))
.setAccessType("online")
.setApprovalPrompt("auto").build();
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
Got the below URL
https://accounts.google.com/o/oauth2/auth?access_type=online&approval_prompt=auto&client_id=1066028402320.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/drive
Run the URL in the internet browser
UserID and password is given as an input in the internet browser to get the unique response token
Now as a part of our development we have completed till step 2 and want to automate the steps 3 & 4 using java code. (After
generating the URL provided with our UserdId and password we should get the response as unique token.)
Expecting your help on this
I would use the following scenario
Set up local webserver to retrieve code from user's oauth redirect
Set redirect_uri of the flow to be local webserver and get auth url
Open browser of auth url for the user
Retrieve code from local webserver and exchange oauth code
Here are some more details with code.
Set up local webserver to retrieve HTTP request
Here is an example of setting local webserver with NanoHttpd
public class OAuthServer extends NanoHTTPD {
/**
* Constructs an HTTP server on given port.
*/
public DebugServer() {
super(8080);
}
#Override
public Response serve(String uri, Method method, Map<String, String> header, Map<String, String> parms, Map<String, String> files) {
bool error = false
string code = null
// User rejected approval
if (parm.containsKey("error")) {
error = true
}
// Here we get the code!
if (parm.containsKey("code")) {
code = parm.get("code")
}
StringBuilder sb = new StringBuilder();
sb.append("<html>");
sb.append("<head><title>Authorization</title></head>");
sb.append("<body>");
if (error) {
sb.append("<h1>User rejected</h1>");
}
if (code==null) {
sb.append("<h1>Unknown Error</h1>");
}
else {
sb.append("<h1>Success</h1>");
}
sb.append("</body>");
sb.append("</html>");
return new Response(sb.toString());
}
public static void main(String[] args) {
ServerRunner.run(OAuthServer.class);
}
}
Set redirect_uri of the flow to be local webserver and get auth url
String url = flow.newAuthorizationUrl().setRedirectUri("http://localhost:8080").build();
Open browser of auth url for the user
// open the default web browser for the HTML page
Desktop.getDesktop().browse(url);
Retrieve code from local webserver and exchange oauth code
Now, user will approve OAuth from the web browser and send code to the local webserver we just started. Now that we have the code retrieved from local webserver, we can parse it into int and authenticate and authorize with it!
Hope this helps
I have a custom login where i get my app authenticated using windows live id authentication ACS.
i am able to do proper login but there is a problem with logout. i get
https://login.live.com/login.srf?wa=wsignout1.0
logout link after de-serializing the ACS json file. but after navigating this it redirects me to msn.com site. how to redirect to my project Default.aspx page. i have a asp.net application. i also tried below code:
string cookieName = "FedAuth";
if (HttpContext.Current.Request.Cookies.AllKeys.Contains(Server.UrlEncode(cookieName)))
{
var cookie = newHttpCookie(Server.UrlEncode(cookieName));
cookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(cookie);
}
WSFederationAuthenticationModule fam = FederatedAuthentication.WSFederationAuthenticationModule;
try
{
FormsAuthentication.SignOut();
}
finally
{
fam.SignOut(true);
}
string reply = fam.Realm + "default.aspx";
// Initiate a Federated sign out request to the STS.SignOutRequestMessage
signOutRequest = newSignOutRequestMessage(newUri(fam.Issuer), reply);
string logoutUrl = signOutRequest.WriteQueryString();
Response.Redirect("default.aspx");
but it didnt work. it logs out and stops to a page called as signout. After logout i want to redirect to my project page.