I have a problem connecting from SITE A to SITE B on the same IIS Server.
SITE A acts as SPA (aspx) and consumes an API (web api) of SITE B, both on .net 4.6.1.
In my deployment env, they are both subdomains of the same domain living on the same V-Server.
If I'm on my dev environment it works with the following code:
protected async Task<HttpResponseMessage> Get(string urlParam = "")
{
string url = _url;
if (!string.IsNullOrWhiteSpace(urlParam))
{
url = $"{_url}?{urlParam}";
}
NetworkCredential credentials = null;
if (!string.IsNullOrEmpty(ServiceUser))
{
credentials = !string.IsNullOrEmpty(ServiceuserDomain)
? new NetworkCredential(ServiceUser, Servicepassword, ServiceuserDomain)
: new NetworkCredential(ServiceUser, Servicepassword);
}
using (var handler = new HttpClientHandler {Credentials = credentials})
{
using (var httpClient = new HttpClient(handler))
{
HttpResponseMessage responseMessage = null;
try
{
responseMessage = await httpClient.GetAsync(url);
}
...
I can also connect with that code to my deployed API (SITE B)
The web.config of SITE A has no "special" configurations. Anonymous Authentication is enabled and Windows Auth disabled.
The web.config of SITE B has the following "special" configuration:
<system.web>
<compilation debug="true" targetFramework="4.6.1" defaultLanguage="c#" />
<httpRuntime targetFramework="4.6.1" />
<customErrors mode="Off" />
<authentication mode="Windows"/>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
<location path="swagger">
<system.web>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="api">
<system.web>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
</system.web>
</location>
Which basically allows anonymous access to the site except for /api and /swagger.
If I test the API call to SITE B from POSTMAN using the new BETA Authentication NTLM it works aswell. The credential are definitly not wrong, but whenever I go throug the log files of SITE B I see:
2019-06-03 12:08:43 212.147.60.15 GET /api/form/ from=0&to=99/ 443 - IP HTTP/1.1 - - sub.domain.ch 401 0 0 2661 114 0
2019-06-03 12:08:43 212.147.60.15 GET /api/form/ from=0&to=99/ 443 - IP HTTP/1.1 - - sub.domain.ch 401 1 3221225581 6661 773 0
Also, both sub-domain on that server have the same IP address, but I don't think that's related.
Unfortunately in my case I cannot access the Windows Server. I just have a PLESK access to manage the domains / files.
Related
I am encountering an infinite redirect loop between login.microsoftonline.com and my application. My project is implementing authentication and authorization in an Asp.net 4.8 web forms project. I am able to add authentication using the default Owin startup file and then require authentication in the web config file. The below works correctly for requiring a user to sign in before being able to access pages/AuthRequired
StartupAuth.CS
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
private static string authority = ConfigurationManager.AppSettings["ida:Authority"];
private static string clientSecret = ConfigurationManager.AppSettings["AppRegistrationSecret-Local"];
public void ConfigureAuth(IAppBuilder app)
{
//for debugging
//IdentityModelEventSource.ShowPII = true;
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
ClientSecret = clientSecret,
RedirectUri = postLogoutRedirectUri,
//This allows multitenant
//https://github.com/Azure-Samples/guidance-identity-management-for-multitenant-apps/blob/master/docs/03-authentication.md
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = (context) =>
{
return Task.FromResult(0);
}
}
}
);
// This makes any middleware defined above this line run before the Authorization rule is applied in web.config
app.UseStageMarker(PipelineStage.Authenticate);
}
}
Web.Config
<configuration>
...
<system.web>
<authentication mode="None" />
</system.web>
<location path="Pages/AuthRequired">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
...
</configuration>
I need to add authorization so that only users with the admin role will be able to access Pages/AuthRequired. I have done that by updating the web config:
<configuration>
...
<system.web>
<authentication mode="None" />
</system.web>
<location path="Pages/AuthRequired">
<system.web>
<authorization>
<allow roles="Admin" />
<deny users="*" />
</authorization>
</system.web>
</location>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
...
</configuration>
Adding authorization to the authenticated page works correctly if the user has that role, but if a user who doesn't have the role tries to access the page they are redirected back to login.microsoftonline.com and then back to the application in an infinite loop.
I can see that Owin UseOpenIdConnectAuthentication is returning a 302 response on unauthorized and that is causing the loop.
How can I change it so that instead of redirecting unauthorized (but authenticated) users to login.microsoftonline.com, that user should be directed to an app page that displays a 401 error?
Please check if below work around helps:
Its usually possible that if forms authentication is enabled, you will be redirected to the login page when status code is 401.
As a workaround try Adding the below to global.asax in the application end request and you can create own unauthorized page if needed and redirect to that.
if (this.Response.StatusCode == 302&& this.Response.StatusCode == 401
&& this.Response.RedirectLocation.ToLower().Contains("login.aspx"))
{
this.Response.StatusCode = 401;
//or Response.Redirect("Unauthorized.aspx");
}
You can also check this > Redirect unauthorised user to message page in ASP .Net. (microsoft.com)
Other references
Prevent redirect to login on status code 401 (Unauthorized)
(microsoft.com)
asp.net - In-place handling (no redirect) of 401 unauthorized? -
Stack Overflow
ASP.NET URL Authorization doesn't appear to interoperate well with OIDC (i.e. Azure AD).
First remove the URL Authorization from your Web.config:
<configuration>
...
<system.web>
<authentication mode="None" />
</system.web>
<location path="Pages/AuthRequired">
<system.web>
-- <authorization>
-- <allow roles="Admin" />
-- <deny users="*" />
-- </authorization>
</system.web>
</location>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
...
</configuration>
Optionally make authenticated required for all pages globally:
<system.web>
<deny users="?" />
</system.web>
You can override this behaviour with <Allow users="?" /> for specific pages i.e. logins/logouts/erorr pages/etc.
Second add authorization logic to your AuthRequired.aspx page:
public partial class AuthRequired {
protected void Page_Load(object sender, EventArgs e)
{
Authorization.AuthorizeAuthRequiredPage();
...
}
}
public static class Authorization
{
public static void AuthorizeAuthRequiredPage()
{
if (!Authorized(HttpContext.User))
{
Redirect("/Anauthorized.aspx");
}
}
private static bool Authorized(User user) => { ... }
}
I'm working on an ASP.Net MVC application. I want to deny access to all users who are unauthenticated or not in an AD group. Only this AD group should have access. The exception to this is the "You Shall Not Pass!" page. Anyone can access that.
In the project root, I have this in my web.config (the rest of the file is trimmed for brevity):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<customErrors mode="On">
<error statusCode="401" redirect="/ui/Other/YouShallNotPass.html" />
</customErrors>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
<authentication mode="Windows" />
<authorization>
<allow roles="allowedrole"/>
<deny users="*"/>
</authorization>
</system.web>
<system.webServer>
<httpErrors>
<remove statusCode="401" />
<error statusCode="401"
subStatusCode="2"
responseMode="ExecuteURL"
path="/ui/Other/YouShallNotPass.html" />
</httpErrors>
</system.webServer>
</configuration>
I have a second web.config sitting next to ui/Other/YouShallNotPass.html. I expect this to allow anyone to access this page, authenticated or otherwise:
<configuration>
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</configuration>
I'm able to test this by setting the AD group to one that doesn't exist. I'm not part of the non-existent group, so I should expect to see the YouShallNotPass.html page.
It's not working as expected. I'm getting the following error in my browser:
Error message 401.2.: Unauthorized: Logon failed due to server configuration. Verify that you have permission to view this directory or page based on the credentials you supplied and the authentication methods enabled on the Web server.
If I request YouShallNotPass.html directly, I can access it after being prompted for a user/pass.
What am I doing incorrectly? Why won't it serve the 401 page when the user isn't authorized?
Check out this question because it explains why your solution won't work.
So once you move to annotate all your secure controller actions with [Authorize] you can add a custom ExceptionFilter
like this
public class HandleUnauthorizedAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
if (filterContext.Exception.GetType() != typeof (SecurityException)) return;
var controllerName = (string) filterContext.RouteData.Values["controller"];
var actionName = (string) filterContext.RouteData.Values["action"];
var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
filterContext.Result = new ViewResult
{
ViewName = "Unauthorized",
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
};
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
Then wiring it up here
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleUnauthorizedAttribute());
}
}
Managed to work around this by adding the following to my global.asax:
protected void Application_EndRequest(object sender, EventArgs e)
{
if (Response.StatusCode != 401)
return;
Response.ClearContent();
Response.WriteFile("~/ui/Other/YouShallNotPass.html");
Response.ContentType = "text/html";
}
I would have preferred using the web.config to do this, though.
how to set up smart-card authorization in web form
i can read ATR of smart card...
try {
m_iCard.Connect( DropDownList1.SelectedItem.Text, SHARE.Shared, PROTOCOL.T0orT1);
try {
// Get the ATR of the card
byte[] atrValue = m_iCard.GetAttribute(SCARD_ATTR_VALUE.ATR_STRING);
} catch {
}
} catch {
}
But further from that no idea.
Do you have the authentication process in place? If not, you can access the link below, it has a tutorial for that:
http://securitythroughabsurdity.com/2007/04/implementing-smartcardauthenticationmod.html
Once the users were authenticated by the SM, you can authorize them:
http://securitythroughabsurdity.com/2007/04/implementing-authorization-in-aspnet.html
You can see on this link the full tutorial:
http://securitythroughabsurdity.com/2007/04/implementing-smartcard-authentication.html
Edited - it’s possible to implement authorization on the following forms:
Declarative
using System.Security.Permissions;
...
[PrincipalPermission(SecurityAction.Demand, Role="Administrator"),
PrincipalPermission(SecurityAction.Demand, Role="Auditors")]
public void DoSomethingImportant()
{
...
}
Imperative
using System.Security.Permissions;
...
public void DoSomethingImportant()
{
PrincipalPermission permCheck = new PrincipalPermission(Nothing, "Administrators");
permCheck.Demand();
}
IPrincipal.IsInRole() Check
if (myPrincipal.IsInRole("Administrators")
{
...
}
Web.Config - Specify access permissions to files and/or folders in the web.config
<configuration>
<system.web>
...
</system.web>
<location path="Admin">
<system.web>
<authorization>
<allow roles="Administrator" />
<deny users="*" />
</authorization>
</system.web>
</location>
<location path="Reports">
<system.web>
<authorization>
<allow roles="Auditor" />
<deny users="*" />
</authorization>
</system.web>
</location>
</configuration>
I have this application where I login by the PC user. I'm using this:
public static bool IsAuthenticated()
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
CurrentUser = Factory.Users.List(item => item.Username.ToLower() == cToLower()).FirstOrDefault();
}
return CurrentUser != null;
}
Note: .List(), is a method I created to list all database Users (in
this case).
Everything works fine. But when I publish my Website on my IIS, HttpContext.Current.User.Identity.Name is returning nothing, no user at all. What is wrong with it? Any suggestion?
You have to enable IIS Windows Authentication and Deny Annomyous acces. You can either configure your IIS or update your configuration file as follows,
<configuration>
<system.web>
<authentication mode="Windows" />
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
i am using windows authentication with my asp.net application
different users will have different access to parts of the website.
i would like to do something like this in the config file:
<appSettings>
<role1>
<user>agordon</user><user>jsmith</user>
</role1>
<role2><user>dtodd</user><user>kveel</user></role2>
</appSettings>
is this possible to do?
when authenticating i would then get the username like this:
string username = HttpContext.Current.User.Identity.Name.ToString();
and check if that user exists in the specific role
Use the <authorization> element:
<configuration>
<system.web>
<authorization>
<allow users="*" />
<deny users="?"/>
</authorization>
</system.web>
</configuration>
You can then modify that for particular parts of your site:
<location path="Pages/Administration">
<system.web>
<authorization>
<deny roles="*"/>
<allow roles="Admin" />
</authorization>
</system.web>
</location>
You can do this, but it's really not the best way.
The problem here is that appSettings are not controlled by the Web.Config schema, so you'll need to programatically enumerate appSettings in a horrible fashion:
if (configurationSettings.HasKey("Role1")) { ... }
else if (configurationSettings.HasKey("Role2")) { ... }
else if (configurationSettings.HasKey("Role3")) { ... }
//continue ad.nauseum; it's not fun - trust me!
I know it's not what you're asking, but If you're using normal ASP.Net webforms then it's a little it of a slog; in each page/control you need to find out the current user and then determine if that user has access and then redirect or continue.
If you use ASP.Net MVC, it's a lot cleaner as you do this with attributes.
Authorize(Roles = "Managers")]
public ActionResult CompanySecrets()
{
return View();
}
What the code there is doing, is saying If the user doesn't have the Managers role, don't give them access.
To provide an opposite example, here's a similar method using Web form (msdn example):
http://support.microsoft.com/kb/311495