IdenityServer4 - doesn't redirect after MFA - identityserver4

My Auth Server uses IdentityServer4.
Redirect configured as follows for a client
RedirectUris = new List<string>
{
"https://localhost:44342/signin-oidc"
}
this works fine for those users for whom MFA is not enabled. But when it is enabled, and kicks in, the redirect doesn't work. After successful 2nd FA, user stays back on the AuthServer page.
Any idea why?

Multifactor authentication is not implemented by Identityserver4. Identityserver4 is about how the third party application gets access to protected resources on behalf of the user.
The means of how the user gets authenticated are out of the identityserver4 scope. In other words, this is not related to identityserver4.
If you're using the identityserver4 quickstart it comes with ASPNET Identity, ASPNET Identity provides you with a local authentication system for ASPNET applications. MultiFactor Authentication is probably there.
Being said that, when you try to POST to the /authorize endpoint (note authorize not authenticate) from your client application IdentityServer tries to authorize your request and to do so it makes you authenticate first, by presenting you the Login Form.
If you look at the Address bar on this point, you'll notice there's an encoded url as returnUrl param, on the controller code you'll see a check that if that param is present, redirect to that url after successful login.
So, check the flow on your application and see where does that parameter get lost on the redirect hell, at some point you're not passing the returnUrl.

Related

What is the right way to start Authorization Code Flow from identity server login page?

I'm trying to implement Authorization Code Flow for SPA React client with ASP.NET Core and IdentityServer4.
There are two scenarios:
1) User open SPA app, we check if he has an access token and if he hasn't we generate url like
/connect/authorize?
client_id=*client_id*&
redirect_uri=*redirect_uri*&
response_type=code&
response_mode=fragment&
state=*some_state*&
nonce=*some_nonce*&
code_challenge=*code_challenge*&
code_challenge_method=S256&
scope=openid profile email
And so Authorization Code Flow starts. This works pretty clear and after all round trips user comes back to SPA app with code then send request for token (include code and code_verifier) then receive it and with happiness in soul continue using our great application.
2) User opens login page directly and here is where I'm stuck. IdentityServer context knows nothing about this user, code challenges etc. because we didn't make request to /connect/authorize before going to this page as in normal flow. What's next?
I can generate /connect/authorize link directly in login page and do ugly redirect to it and then back to login page (what I don't want to do honestly), but how my SPA app will know what code_verifier I generate here? Of course I can store it in some shared cross-domain cookie, but here should be something better approach I believe.
Another solution I can redirect user from login page to my app, it recognizes that user not authorized and we start scenario #1. Also not my go to approach I think.
What should I do in case user opens my identity server page directly?
Is this possible using Authorization Code Flow or should I consider combine some other flows with this one?
I don't want to use Implicit Flow due to new recommendation from OAuth 2.0 specification.
Quite a simple answer to this - in your second scenario - if your user opens IDP login page directly, they didn't want to go to your app. It's the same if you were using Google or Facebook or one of the other known IDP's for your SPA and as a user I just went to their login page instead. They couldn't possibly know if my intention was to ever come to login so that I am later redirected to your SPA.
Now having said all that - what you could do to make this work somewhat seamless - is to redirect to your SPA's protected page after the user logs in through Identity Server 4 (that's simple because you own the login pages and there is no OAuth involved here). Your SPA would then be triggered to initiate the OAuth2 flow and would redirect back to Identity Server 4. The user has already logged in just seconds ago here though, so the login procedure would be skipped and user would either be presented with consent page or if your client is configured to skip consent page - user would be redirected back to your SPA with the usual tokens and such.
So to break it down into the flow:
User Accesses IDS4 Login Page -> User Enters Credentials -> IDS4
Authenticates User and Redirects to your SPA protected page -> Your
SPA initiates OAuth2 flow and redirects back to IDS4 -> IDS4 displays
consent page -> IDS4 issues auth code back to your SPA.
There is ofcourse extra step here that your SPA will exchange auth code for access token, but I omitted it for clarity purpose as it's not relevant to the question.

How does Single-logout works with OKTA(IDP)-Shibboleth(SP)-App

OKTA-Shibboleth(Apache)-Nakisa(Tomcat)
SSO is working for logging-in.
Now, I need to configure Logout. So, user logs out from the app, user needs to be redirected to OKTA page with tiles.
But, currently,user is redirected to the app again.
It's sending user to /logout?redirect=default.html but that default.html is captured by Apache rule and logging user back in.
It looks like it needs to hit
https://xxxx/Shibboleth.sso/Logout. When I access this url, it says logout is successfully done although it's not going back to OKTA. Does that mean that in the App's logout setting, they need to redirect to this?
But, how do I make user to go back to IdP(i.e OKTA) again?
This is what I assume that will happen.
Logout button click > logout from Shibboleth > return to OKTA so user can click other tiles.
Something to configure Shibboleth2.xml?
Document says i just need to configure the following which is there by default.
<!-- SAML and local-only logout. -->
<Logout>SAML2 Local</Logout>
But, how does it redirect user to OKTA(IdP) once user log out completes.
Is it configured in IdP's metadata ?
You can redirect the user after a local logout event anywhere you'd like, via passing the ?return= parameter a URL-encoded destination, i.e. you should update your logout link to:
https://xxxx/Shibboleth.sso/Logout?return=https%3A%2F%2Fgoogle.com
in order to redirect folks to Google once logout has taken place.
Now, you only need an Okta URL to return folks to... so I think if your client's Okta tenant is "foobar.okta.com", redirecting them after local logout to the Okta login page shouldn't prompt them to login, since they will already have the Okta Session... so maybe try:
https://xxxx/Shibboleth.sso/Logout?return=https%3A%2F%2Ffoobar.okta.com%2Flogin
Of course, you'll need to test that... but it should work, and on the off chance that the user's Shibboleth SP session was active, and their Okta session invalidated through some other mechanism, that'll just return them to their regular Okta login page.
You can obviously redirect them to any endpoint with the return parameter, for example, whatever Okta's logout URL (if you wanted to kill their Okta session too).
The only logout that's configurable by Metadata is SLO (single logout), i.e. if you wanted it to, Shibboleth can redirect the user to Okta after they complete the logout of the SP session, along with a specially-craft <LogoutRequest> assertion payload, which Okta would parse and act on in any number of ways, i.e. killing the user's Okta session, propagating Okta-initiated subsequent <LogoutRequest> assertions to other Service Providers, etc. In practice, this never really works, because such configurations are very difficult to get working between all of the relevant parties.

how to integrate regular username/password login with 3rd party social login for a Spring Boot + Angular single page web app?

I have a Angular + Spring boot single page web app. The server also acts as an Auth Server which issues tokens for the angular app to use to make Restful API calls.
My old login flow uses a grant_type=password POST call to the /oauth/token endpoint to get a Bearer token. And all further API calls on behalf of the user will include the Bearer token as the "Authorization" http header.
Now I need to integrate social login (facebook, twitter, etc.), which means I don't have username/password to generate tokens so I'm not sure how to make it work.
I have been using the following two tutorials as my template:
Spring Security and Angular JS
Spring Boot and OAuth
In the first tutorial's oauth-vanilla example, the username passwork login flow brings up the authorization page. But I'd like to have the traditional username/password form login experience (log user in directly instead of showing the Authorization page).
In the second tutorial, after facebook login, I'd like to use the facebook id to look up my internal user database and create a new user if not exist and logs him in as the user. And use the internal db user's identity and authorities to authorize future API calls to my API server.
I have a stripped down sample at at
https://github.com/dingquan/spring-angular-oauth
I can make POST calls to /oauth/token endpoint and use the returned token to make further api calls to my protected /api/blogs endpoint. But I haven't figure out how to make the following things work:
Username/password login that will create a session cookie so I don't need to send the Authorization bearer token for future API calls to the resource endpoint
After facebook login (the facebook login link is under the username/password login form), calls to my endpoint still fails with 401 error (I have a "test" button that makes a get call to /api/blogs, you can click on it to see the behavior). So what am I missing to make the API call succeed?
=== UPDATE ===
Just to clarify. Here are the goals I'm trying to achieve:
multiple ways of authentication (traditional username/password, third party oauth login such as facebook, possibly cellphone number + SMS code in the future)
we do need our own user model backed by DB to store other user attributes, pure social login is not enough
social login needs to be implicit. Meaning user should not be required to create a user account in our system manually once they login through a 3rd party (facebook, etc.). We're not just grabbing users' social profile data to pre-populate the registration form. We want to create new DB users automatically behind the scene if no existing db user is associated with the given external social account. i.e. if user is logged in through facebook, they don't need to enter username/password. Authentication through facebook will automatically log the user into our system as well and user should be able to access restricted resources after facebook login.
There's some confusion that I might be asking people to put their facebook username/password in a login form hosted by my app and I'll login facebook on behalf of the user. That's not what I was asking for.
You don't need such a complicated configuration. Add #EnableOAuth2Sso to your MainConfiguration and set appropriate application properties.
Here is what I have done in order to use Facebook as a authorization server.
a) Remove clientId and authServer from UserServiceImpl. Otherwise you'll be forced to configure an authorization server that is not needed.
b) Remove AuthorizationServerConfiguration completely.
c) Add #EnableWebSecurity and #EnableOAuth2Sso to your MainConfiguration.
d) Change MainConfiguration::configure to
http
.logout().logoutSuccessUrl("/").permitAll().and()
.authorizeRequests().antMatchers("/", "/login", "/home.html").permitAll()
.anyRequest().authenticated()
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
e) Delete everything else except nested class AuthenticationSecurity from MainConfiguration.
f) Change ResourceServerConfiguration::configure(HttpSecurity) to
http.antMatcher("/api/**").authorizeRequests().anyRequest().authenticated();
f) Remove attribute tokenStore and method ResourceServerConfiguration::configure(ResourceServerSecurityConfigurer) from ResourceServerConfiguration.
g) Remove configuration block security and facebook from application.yml. Instead add this
security:
oauth2:
client:
client-id: <CLIENT_ID>
token-name: oauth_token
authentication-scheme: query
client-authentication-scheme: form
access-token-uri: https://graph.facebook.com/oauth/access_token
user-authorization-uri: https://www.facebook.com/dialog/oauth
resource:
user-info-uri: https://graph.facebook.com/me
client-id: <CLIENT_ID>
client-secret: <CLIENT_SECRET>
token-type: code
h) In index.html change login to login.
i) Replace the content of hello.js with this one.
But I'd like to have the traditional username/password form login experience (log user in directly instead of showing the Authorization page).
I would never use a site that requires my credentials without redirecting me to the origin! I don't know you and you are under suspicion being a phishing site.
You should really reconsider your decision.
Btw, I created a pull request with these changes.

Are there security concerns exposing the clientId and tenant in client side code when using adal/adal-angular.js

I'm in the process of implementing AAD single sign on in our application and we will be using the adal.js/adal-angular.js library with our MEAN stack application. Part of initializing the library is to call init() and provide the tenant and clientId
adalProvider.init(
{
tenant: "mycompany.onmicrosoft.com",
clientId: "05bdd8d7-XXXX-XXXX-XXXX-5f2769f8b9b6"
},
$httpProvider
);
for example.
If someone views the source and takes the tenant and clientId can they use that somehow in their own application maliciously?
Does AzureAD check the URL the request came from and block it if it's not the configured login url?
Seems as though the clientId is more like a public key but if the only 2 things needed for an app to trigger authentication with AzureAD is the tenant and clientId and those are exposed client side in source code that someone could use them to create a phishing site X or to grab id_tokens if the request is redirected back to their site X rather than the original site
Does Azure rely on the configured settings in the application setup and protect against this?
I'm still getting a grasp on the OpenID Connect and OAUTH 2.0 finer points so forgive me if this question has an obvious answer.
Adal.js uses the Implicit flow (as per OpenID connect / oAuth 2 specifications) and exposing the ClientID (and tenant id of AAD) doesn't pose any security risk.
While registering the Clients in Azure AD administration panel, we specify a Redirect URI for the client. This is the Application URL for which users will get redirected after successful authentication.
So even if a malicious client tries to use your clientid and tenant id, the users will be redirected back to the registered URI(which is your app) after authentication and not to the malicious site
In implicit flow the application doesn't collect any username / password, IDP/OP (i.e AAD) manages this part - so user credentials won't be compromised as well
**For other flow types (Authorization code, Client credentials,etc) we have something called client-password along with ClientID. This shouldn't be exposed to public clients.

Missing Application Claims when completed SignUp policy on Azure B2C

I am implementing the Azure B2C preview in our mobile app but I am having trouble retrieving the application claims once the Signup policy has completed and the redirect_uri is called. I have specified the claims I need returned through the "Application claims" section of the policy blade and similarly through the other two policies (Sign-in and Profile) but I never receive a JWT along with the access code on the callback to the redirect_uri.
I have also tried HTTP and HTTPS in the redirect_uri and using the different response_mode settings but all i get is the code returned.
Am i missing something, or does the signup policy not support returning other claims at this point. I was planning on using them to send a welcome email to the new user.
I think i may have just realised - i need to make a call to the token endpoint to swap my code for the id_token and then i can get the claims.

Resources