I've an issue on this feature.
SignIn action works well with ADFS and return to AuthServices/Acs
But Logout action don't call ADFS and redirect directly to returnUrl parameters (checked it with fiddler).
I'm calling this link : /AuthServices/Logout?ReturnUrl=~/&Status=LoggedOut
web.config is set up as this :
<kentor.authServices entityId="https://localhost:2181/AuthServices" returnUrl="https://localhost:2181/">
<identityProviders>
<add
entityId="https://ADFS DOMAIN/adfs/services/trust"
signOnUrl="https://ADFS DOMAIN/adfs/ls"
logoutUrl="https://ADFS DOMAIN/adfs/ls/?wa=wsignout1.0"
binding="HttpPost"
allowUnsolicitedAuthnResponse="true"
metadataLocation="https://ADFS DOMAIN/FederationMetadata/2007-06/FederationMetadata.xml"
wantAuthnRequestsSigned="true">
<signingCertificate fileName="~/App_Data/*****.cer" />
</add>
</identityProviders>
</kentor.authServices>
If I launch https://ADFS DOMAIN/adfs/ls/?wa=wsignout1.0 on another tabs, it is working, I return on signin page from my website.
So it seems to be an internal issue to retrieve logouturl and send it ?
Thanks for helps.
There are a number of requirements that need to be met before logout request will be issued:
You need to have a http://kentor.se/AuthServices/LogoutNameIdentifier claim and its issuer has to match the IDP that you're trying to logout from.
You need to have http://kentor.se/AuthServices/SessionIndex claim.
Your AuthServices IDP configuration needs a logoutUrl (I see you've specified this but probably it's easier to let AuthServices read it from the metadata)
You have specified a ServiceCertificate with either Signing or Both usage (i.e. not just Encryption)
Your AuthServices IDP configuration has DisableOutboundLogoutRequests =
false (this is the default)
Missing claims (first two points) is the most likely issue if you have some claims transformation happening during login or you are not retaining the original ClaimsIdentity. See also the documentation regarding ClaimsAuthenticationManager, e.g. https://github.com/KentorIT/authservices/blob/master/doc/ClaimsAuthenticationManager.md
You can turn on logging and see which of these points are failing:
https://github.com/KentorIT/authservices/blob/v0.21.2/Kentor.AuthServices/WebSSO/LogOutCommand.cs#L155-L170
Related
Ok, first question ever so be gentle. I've been struggling with this for about a week now and i am finally ready to accept defeat and ask for help.
Here's what is happening. I have an IdentityServer4 IDP, an API and an MVC Core Client. I am also interacting with 2 external OAuth2 IDPs provided by the business client.
My problem scenario is this:
The user logs in through my IDP(or potentially one of the external ones)
Once the user is in the Mvc Client they hit the back button on their browser
Which takes them back to the login page(whichever one they used)
They reenter the credentials(login again)
When redirected back(either to the MVC in the case of my IDP, or my IDP in the case of one of the external IDPs) i get RemoteFailure event with the message:correlation failed error
The problem seems, to me, to be the fact that you are trying to login when you are already logged in(or something). I've managed to deal with the case of logging in at my IDP, since the back button step takes the user to my Login action on the Controller(I then check if a user is authenticated and send them back to the MVC without showing them any page) but with the other two IDPs the back button does not hit any code in my IDP. Here are the config options for one of the OAuth2 external IDPs:
.AddOAuth(AppSettings.ExternalProvidersSettings.LoginProviderName, ExternalProviders.LoginLabel, o =>
{
o.ClientId = "clientId";
o.ClientSecret = "clientSecret";
o.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
o.CallbackPath = PathString.FromUriComponent(AppSettings.ExternalProvidersSettings.LoginCallbackPath);
o.AuthorizationEndpoint = AppSettings.ExternalProvidersSettings.LoginAuthorizationEndpoint;
o.TokenEndpoint = AppSettings.ExternalProvidersSettings.LoginTokenEndpoint;
o.Scope.Add("openid");
o.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
//stuff
},
OnRemoteFailure = async context =>
{
if (!HostingEnvironment.IsDevelopment())
{
context.Response.Redirect($"/home/error");
context.HandleResponse();
}
}
};
}
The other one is the same. Since the error is exactly the same regardless of the IDP used, i am guessing it is not something native to OIDC but to OAuth middleware and the code(config options) they share, so i am not going to show the OIDC config on the MVC client(unless you insist). Given how simple the repro steps are i thought i would find an answer and explanation to my problem pretty fast, but i was not able to. Maybe the fix is trivial and i am just blind. Regardless of the situation, i would apreciate help.
I could reproduce your issue.
When the user goes back to the login screen after successfully logging in,
it might well be that the query parameters in the URL of that page are no longer valid.
Don't think this is an issue specific to Identity Server.
You may read
https://github.com/IdentityServer/IdentityServer4/issues/1251
https://github.com/IdentityServer/IdentityServer4/issues/720
Not sure how to prevent this from happening though.
I'm building a Single Page Application using Spring Social and Spring Security generated by JHipster.
I'm trying to capture the original query parameters after a user has been authenticated by some social authentication provider.
Example:
calling /signin/someprovider?show=someEntityId and after a successful authentication redirects the user to /signup/ , I need a way to fetch 'someEntityID'.
I assume different http calls make it difficult to pass/store the parameters around.
Is there some Spring built-in functionality I can use/reuse or how does one solve this problem?
UPDATE
The thread of requests looks like this:
(1) browser-> http://localhost:9060/signin/authenticationProvider?show=**someEntityId**
<- redirect to https://authenticationProvider... &state=SomeState
(2) browser -> https://authenticationProvider
<- redirect to http://localhost:9060/signin/google?state=SomeState&code=SomeCode
(3) browser-> http://localhost:9060/signin/authenticationProvider?state=SomeState&code=SomeCode
<- redirect to http://localhost:9060/social/signup
(4) browser -> http://localhost:9060/social/signup
This ends up in
#GetMapping("/signup")
public RedirectView signUp(WebRequest webRequest, #CookieValue(name = "NG_TRANSLATE_LANG_KEY", required = false, defaultValue = Constants.DEFAULT_LANGUAGE) String langKey) {
try {
Connection<?> connection = providerSignInUtils.getConnectionFromSession(webRequest);
socialService.createSocialUser(connection, langKey.replace("\"", ""));
At this point it want to call a function with the original parameter someEntityId.
According to google oauth2 redirect_uri with several parameters the ?show=someEntityId parameter should be encoded in the state parameter of the Oauth2 request in order to survive
from (1) to (3). In (3) the state parameter has to be added to the redirect uri, such that the original parameter can be decoded in (4).
It looks like a lot of work, or am I missing something? It would be nice if there would be a way to have a session variable in which I could store the parameters at (1) and fetch them again when in (4).
Since version 1.1.3 Spring Social creates the state parameter on its own and uses it as a CSRF token, see https://pivotal.io/security/cve-2015-5258 - therefore you can (and should not) encode additional parameters in the state parameter.
Instead if the provider sign is enabled with a ProviderSignInController, a ProviderSignInInterceptor can be used to store such parameters intermediately in the session (in preSignIn(...) and postSignIn(...)).
I guess there is a similar approach if a SocialAuthenticationFilter is used.
I am trying to login using the <cfoauth> tag, but am not able to do so. It is showing
Error: invalid_request
Below is my code.
<cfoauth
type = "google"
clientid = "*****************es7t0r6qc"
secretkey = "**************tSF97WncM5ix9jtvD200"
result = "result"
scope="https://www.googleapis.com/auth/plus.me"
redirecturi = "http://192.168.9.126:8088/bootstrap-blog-template/tpl/cfoauth.cfm"
>
Please help.
The problem seems to be related to redirecturi. You need to provide an existing and valid URL of the page on which you want to redirect to after authentication.
For example if local URL of the page you are testing the code is http://localhost:8500/cfbuster/login.cfm , then redirecturi can be same page i.e. http://localhost:8500/cfbuster/login.cfm or another page http://localhost:8500/cfbuster/doLogin.cfm.
Apart from this, the redirecturi you wish to set, should be saved in Google Developers Consele >> API Manager >> Credentials screen under Authorized redirect URIs. In my case it is http://localhost:8500/cfbuster/test.cfm
In case the redirecturi passed is non existing or not saved in the API Authorized redirect URIs screen we get following error message:
Note 1: The redirecturi Must have a protocol. Cannot contain URL fragments or relative paths. Cannot be a public IP address.
Note 2: https://www.googleapis.com/auth/plus.login is the recommended login scope. The https://www.googleapis.com/auth/plus.me scope is not recommended as a login scope because, for users who have not upgraded to Google+, it does not return the user's name or email address.
I have setup my facebook auth per passportjs docs:
var passport = require('passport')
, FacebookStrategy = require('passport-facebook').Strategy;
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "http://www.example.com/facebook/callback"
},
function(accessToken, refreshToken, profile, done) { ... });
}
));
app.get('/login/facebook', passport.authenticate('facebook'))
.get('/facebook/callback', passport.authenticate('facebook', {successRedirect: '/', failureRedirect: '/login'}));
All this works fine. However, there are cases (such as token expiration) when I want to automatically redirect the user to the page that the user was on before initiating the login request. So I tried to plumb a query string param through the login request (from client to server to facebook and back). But I cant see a way to specify that in the callbackURL.
Furthermore, when I tried hard-coding some context param to the config callbackURL (eg: "http://www.example.com/facebook/callback?redir=lastUserPage") I get an OAuth parse error. Interestingly enough, Facebook does respond correctly with the access code as well as the redir param, but it fails with OAUTH exception:
FacebookTokenError: Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request
at Strategy.parseErrorResponse (C:\Sources\node_modules\passport-facebook\lib\strategy.js:198:12)
at Strategy.OAuth2Strategy._createOAuthError (C:\Sources\node_modules\passport-facebook\node_modules\passport-oauth2\lib\strategy.js:345:16)
at C:\Sources\node_modules\passport-facebook\node_modules\passport-oauth2\lib\strategy.js:171:43
at C:\Sources\node_modules\passport-facebook\node_modules\passport-oauth2\node_modules\oauth\lib\oauth2.js:177:18
at passBackControl (C:\Sources\node_modules\passport-facebook\node_modules\passport-oauth2\node_modules\oauth\lib\oauth2.js:124:9)
at IncomingMessage.<anonymous> (C:\Sources\node_modules\passport-facebook\node_modules\passport-oauth2\node_modules\oauth\lib\oauth2.js:143:7)
at IncomingMessage.emit (events.js:117:20)
at _stream_readable.js:943:16
at process._tickCallback (node.js:419:13)
Note that I had this working using WIF before. I don't see any security concerns with passing additional query string parameters through the OAuth process..
Any idea how I can get past this?
I'm not sure how to do what you're asking, but for your desired end goal you could:
Save a cookie before authenticating
Authenticate the user
on the resulting callback page, check for the cookie and redirect if present.
Wouldn't this work just as easily?
I am using the following code in my logout button :
<a id="login-control-logout" href="${createLink(controller:'LicGenerator', action:'logout')}"><i class="icon-off"></i> Logout</a></li>
Inside my controller, I am using the following code :
def logout() {
request.getSession().invalidate()
response.setHeader("Cache-Control","no-cache,no-store,must-revalidate")
response.setHeader("Pragma","no-cache")
response.setDateHeader("Expires", 0)
redirect(uri:'/login.html')
}
It goes to login.html, but when I enter the username and password again, it doesn't log me back in and throws an error
type Status report
message /LicGenerator/j_security_check
description The requested resource (/LicGenerator/j_security_check) is not available.
When I refresh the browser, I got this error :
type Status report
message Invalid direct reference to form login page
description The request sent by the client was syntactically incorrect (Invalid direct reference to form login page).
Also, the back button takes me to page even though I added cache control to response.
Simply invalidating your session for spring security is probably not advisable. As there is a SecuritySession which also has cookies. It may be better to use whats provided by spring security already.
import grails.plugin.springsecurity.SpringSecurityUtils
redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl
Then you can configure your default login url via the config options for the spring security plugin