WIF, ADFS 2.0, wsignoutcleanup1.0 and wreply - asp.net

I have set up a WIF web application, a custom STS and an ADFS 2.0 instance as the go between. I am having a hard time understanding the sign out process for my application. Currently, when my user clicks the sign out button, I am calling this code:
WSFederationAuthenticationModule.FederatedSignOut(null, new Uri("https://myrelyingpartyapp.com/?wa=wsignoutcleanup1.0"));
If I use this code, it works fine. All of the cookies and sessions are disposed of correctly. The only problem is that the browser just displays a little green check after the process is over. Obviously, I want to be redirected back to the login page of the STS. To accomplish this I attempted the following code:
WSFederationAuthenticationModule.FederatedSignOut(null, new Uri("https://myrelyingpartyapp.com/?wa=wsignoutcleanup1.0&wreply=" + HttpUtility.UrlEncode("https://myrelyingpartyapp.com/Default.aspx")));
My belief was that the wreply would cause the user to be redirected back to my relying party app where they would be unauthorized and therefore be redirected back to the STS login page. Instead this causes an error in ADFS (which I cannot see because of their helpful error page.) No matter what url I use for wreply, the error is thrown. Am I using wsignoutcleanup1.0 correctly? Just for reference, here is the code in my STS where I handle sign in/sign out requests:
if (action == "wsignin1.0")
{
SignInRequestMessage signInRequestMessage = (SignInRequestMessage)WSFederationMessage.CreateFromUri(Request.Url);
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
SecurityTokenService securityTokenService = new CustomSecurityTokenService(CustomSecurityTokenServiceConfiguration.Current);
SignInResponseMessage signInResponseMessage = FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(signInRequestMessage, User as ClaimsPrincipal, securityTokenService);
FederatedPassiveSecurityTokenServiceOperations.ProcessSignInResponse(signInResponseMessage, Response);
}
else
{
throw new UnauthorizedAccessException();
}
}
else if (action == "wsignout1.0")
{
SignOutRequestMessage signOutRequestMessage = (SignOutRequestMessage)WSFederationMessage.CreateFromUri(Request.Url);
FederatedPassiveSecurityTokenServiceOperations.ProcessSignOutRequest(signOutRequestMessage, User as ClaimsPrincipal, signOutRequestMessage.Reply, Response);
}

All I needed for correct behavior was correct logout code. This code eventually logged my user out and did a proper cleanup:
var module = FederatedAuthentication.WSFederationAuthenticationModule;
module.SignOut(false);
var request = new SignOutRequestMessage(new Uri(module.Issuer), module.Realm);
Response.Redirect(request.WriteQueryString());
This code was put in the event handler of my logout button on my relying party app.

Related

Disable or Unregistered Meteor.Accounts default login handler (loginWithPassword)

I have created my own custom login handler to authenticate users.
loginWithPasswordPlatfrom(user,passwd,platformId)
I want to disable the default login method loginWithPassword(user,password) of the meteor and force clients (android, ios, web) to use my custom method.
but what happened if client call login with user and password parameter it is successfully logedin because default login is still registered in a meteor.
please suggest how to disable or unregister a login handler in meteor accounts.
You can modify Accounts._loginHandlers on the server and throw out the default login method. Accounts.loginWithPassword() is then no longer possible on the client.
var hs = []
for(var i = 0; i < Accounts._loginHandlers.length; i++) {
if(Accounts._loginHandlers[i].name != 'password') hs.push(Accounts._loginHandlers[i])
}
Accounts._loginHandlers = hs

Meteor.js google account : filter email and force account choser

In my Meteor.js application, I'm using the accounts-google package in order to be connected with a google account. I have two questions about it.
First, is there a simple way to filter the account used? I would like that the users can connect only with google accounts belonging to my company. Our google account mails end with #mycompany.com. So it would be a simple mail filtering.
I already done that with some post log in hooks but I was wondering if there was a simpler way for doing it.
My second question is how to force the opening of the google account choser. For now, if I try to connect with a wrong google account, and if I only added this account (like in gmail, drive, etc), the google choser doesn't pop and automatically connect with this wrong account. So, in this case, the user is totally blocked (my application disconnect him if he tries to log in with a wrong account but the google account module doesn't propose him to connect with another account).
Thank you for your help.
In order to restrict signup/login to your domain, simply do on the server:
var checkEmailAgainstAllowed = function(email) {
var allowedDomains = ['mycompanydomain.com'];
var allowedEmails = ['otheruser#fromotherdomain.com','anotheruser#fromanotherdomain.com'];
var domain = email.replace(/.*#/,'').toLowerCase();
email = email.toLowerCase();
return _.contains(allowedEmails, email) || _.contains(allowedDomains, domain);
};
Accounts.config({
restrictCreationByEmailDomain: function(email) {
if (!email) {
throw new Meteor.Error(403,'This email address is not allowed');
}
if (!checkEmailAgainstAllowed(email)) {
throw new Meteor.Error(403,'This email domain is not allowed');
}
return true;
}
});
And to login, you'll need on the client:
Meteor.loginWithGoogle({
forceApprovalPrompt: true, //this is what you want, to rerequest approval each time that prompts the google login prompt
loginStyle : "redirect", //or not, depending on your need
requestPermissions : ['profile', 'email'],
requestOfflineToken: true
}, function (err) {
if (err)
// set a session variable to display later if there is a login error
Session.set('loginError', 'reason: ' + err.reason + ' message: ' + err.message || 'Unknown error');
});
Side note:
Alternatively, you can set up your routes so that every time a new route is called, you login, and every time a route is destroyed or on windows's unload, you call logout. This causes login/logout roundtrip everytime the route changes, but you'll make sure that the new user always has a fresh session
Edit:
When you log out of your meteor app, you don't log out of google. That's how oauth works. So, basically, if you want a meteor log out to also log the user out of their google account, so that the next time they come back, they need to provide credentials again, you should do:
Meteor.logout(function(e) {
if (e) {
console.log("Could not log the user out")
} else {
window.location.replace('https://accounts.google.com/Logout');
}
});
This uses the callback of Meteor.logout() so that when the logout is successfull, the user is redirected to google's central account logout url where the user is also logged out of all google services.

JSF commandlink incorrect navigation

Before asking this questions I have carefully assessed the feasibility to solve the following problem.
I have an external link being fired from an email viewRequest.xhtml?requestID=6. I use a filter to intercept the incoming request and in case the user is not authenticated it is forwarded to the login.xhtml page. After the user is authenticated the request is forwarded by FacesContext.getCurrentInstane().getExternalContext().redirect(redirected-url) Then it displays the page successfully.
Now if try to logout from same page i.e, viewRequest.xhtml page, the requested URI is viewRequest.xhtml again which takes me to the same page instead of logging out and redirect me to the login page.
I have the real concern of why the request.getRequestedURI in filter is still viewRequest.xhtml instead of login.xhtml
Code for reference
AuthenticationFilter - User is un-authenticated - Adding requested email link in session
String from = req.getRequestURI();
if (req.getQueryString() != null) from += "?" + req.getQueryString();
req.getSession().setAttribute("from", from);
res.sendRedirect(req.getContextPath() + "/faces/pages/login.xhtml");
After user is logged in
if (from != null && !from.isEmpty()) {
externalContext.getSessionMap().remove("from");
externalContext.redirect(from); *-----------Original URL re-direction---------*
return null;
}
else{
result = "adminHome";
}
Now we are in viewRequest.xhtml page - loaded successfully - Now clicked on Log out
String from = req.getRequestURI(); <!--FILTER-->
The value of requestedURI is still viewRequest.xhtml
logout() in LoginController.java
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return login;
Please help. Thank you very much.

DotNetOpenAuth Failing to work on Live Server

I worked on a sample application integrating OpenID into ASP.NET Web Forms. It works fine when hosted locally on my machine. However, when I uploaded the application to a live server, it started giving "Login Failed".
You can try a sample here: http://samples.bhaidar.net/openidsso
Any ideas?
Here is the source code that fails to process the OpenID response:
private void HandleOpenIdProviderResponse()
{
// Define a new instance of OpenIdRelyingParty class
using (var openid = new OpenIdRelyingParty())
{
// Get authentication response from OpenId Provider Create IAuthenticationResponse instance to be used
// to retreive the response from OP
var response = openid.GetResponse();
// No authentication request was sent
if (response == null) return;
switch (response.Status)
{
// If user was authenticated
case AuthenticationStatus.Authenticated:
// This is where you would look for any OpenID extension responses included
// in the authentication assertion.
var fetchResponse = response.GetExtension<FetchResponse>();
// Store the "Queried Fields"
Session["FetchResponse"] = fetchResponse;
// Use FormsAuthentication to tell ASP.NET that the user is now logged in,
// with the OpenID Claimed Identifier as their username.
FormsAuthentication.RedirectFromLoginPage(response.ClaimedIdentifier, false);
break;
// User has cancelled the OpenID Dance
case AuthenticationStatus.Canceled:
this.loginCanceledLabel.Visible = true;
break;
// Authentication failed
case AuthenticationStatus.Failed:
this.loginFailedLabel.Visible = true;
break;
}
}
As Andrew suggested, check the exception. In my case, my production server's time & date were off and it wouldn't authenticate because the ticket expired.
Turn on logging on your live server and inspect them for additional diagnostics. It's most likely a firewall or permissions problem on your server that prevents outbound HTTP requests.
You may also find it useful to look at the IAuthenticationResponse.Exception property when an authentication fails for clues.

ASP.NET Windows Authentication logout

How do you logout when using Windows authentication in ASP.NET like this web.config?
<authentication mode="Windows" />
I've already tried the following unsuccessfully. It redirects, but does not log out the user.
void logoutButton_Click(object sender, EventArgs e) {
HttpContext.Current.Session.Clear();
HttpContext.Current.Session.Abandon();
ViewState.Clear();
FormsAuthentication.SignOut();
Response.Redirect("/");
}
Background Info:
I have to use Windows authentication because I need to impersonate the identity using Active Directory to gain access to local files. And I cannot impersonate using Forms authentication because the HttpContext.Current.User.Identity won't be a WindowsIdentity.
Impersonate using Forms Authentication
No server-side logout button will work when using "Windows" authentication. You must use "Forms" authentication if you want a logout button, or close the user's browser.
For IE browsers only, you can use the following javascript to logout the user if using Windows Authentication. (Note: closing the browser isn't required, but recommended since the user might be using a non-IE browser).
If the user clicks "No" to close the browser, then the user will be prompted for a username/password if they attempt to access a page on the site that requires authentication.
try {
document.execCommand("ClearAuthenticationCache");
}
catch (e) { }
window.close();
This code was taken from SharePoint's Signout.aspx page.
Windows authentication works at the IIS level by passing your Windows authentication token. Since authentication occurs at the IIS level you cannot actually log out from application code. However, there seems to be an answer to your problem here. It is the second question addressed and essentially involves using Forms Authentication and the LogonUser Windows api.
I had a SharePoint application with Windows authentication, I needed automatic logout after 15 minutes. I mixed up some codes and here is the result. it works in IE properly.
<script type="text/javascript">
var t;
window.onload = resetTimer;
document.onmousemove = resetTimer;
document.onkeypress = resetTimer;
function logout() {
try {
document.execCommand("ClearAuthenticationCache");
window.location.href = window.location.protocol.replace(/\:/g, '') + "://" + window.location.host + "/_layouts/customlogin14.aspx";
}
catch (e) { }
}
function resetTimer() {
window.clearTimeout(t);
t = window.setTimeout(logout, 900000);
}
put these codes in your master page, after 15 mins idle time you will see the login page.
hope this help somebody
I have this working using JavaScript in both IE and Firefox, though it logs you out of everything you're logged into in IE. It sort of works in Safari, but Safari throws up a phishing warning. Doesn't work in Opera.
try {
if (document.all) {
document.execCommand("ClearAuthenticationCache");
window.location = "/";
} else {
window.location = "http://logout:logout#example.com";
}
} catch (e) {
alert("It was not possible to clear your credentials from browser cache. Please, close your browser window to ensure that you are completely logout of system.");
self.close();
}
The best answers I have seen are found in related StackOverFlow questions:
Is there a browser equivalent to IE's ClearAuthenticationCache?
and
Logging a user out when using HTTP Basic authentication
Basically you need to send a AJAX request to the server with invalid credentials and have the server accept them.
Had alot of trouble with this, below is the code that works, hopefully someone finds it useful.
foreach (var cookie in Request.Cookies.Keys)
{
Response.Cookies.Delete(cookie);
}
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
Response.Cookies.Append("EdgeAccessCookie", "", new Microsoft.AspNetCore.Http.CookieOptions()
{
Path = "/",
HttpOnly = true,
SameSite = SameSiteMode.Lax, Expires = DateTime.Now.AddDays(-1)
});
Response.Redirect("https://adfs.[sitename].com/adfs/ls?wa=wsignout1.0");
I think you should use forms auth, but you can use ldap windows user account in forms like this:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "mypassword");
}

Resources