I'm attempting to add OAuth support to an existing Spring webapp to allow people to login with their Google/Facebook/Twitter/etc. accounts. To do this I'm using the 'spring-social' framework, and the 'spring-social-google' library for it. I'm also trying to do this while working within a number of constraints:
The existing webapp does not use spring-security for authentication or for controlling access to resources, it provides its own form-based authentication.
The existing webapp does not track the authenticated user details using the servlet-container's Principal, instead it stores a reference to the authenticated user in the HTTP session.
The existing webapp does not (and cannot) have a Spring DispatcherServlet bound to the webapp root URL (i.e. /).
Accounts in the database are uniquely keyed by e-mail, so really all I'm attempting to do is glue together a flow that goes roughly like:
Login Page (user chooses between OAuth and direct login)
-> <Provider OAuth Flow> (user completes OAuth authorization)
-> OAuth Callback URL (grab user email, check for existing account, create if needed)
-> Post-login Landing Page (done)
Anyhow, the limitations noted above caused a variety of problems, most of which I've managed to find workarounds for. However I'm getting some bizarre behavior from the Google OAuth connector (Twitter and Facebook appear to work correctly). Basically, it appears that it is not sending the OAuth clientId or clientSecret during the final request to Google:
DEBUG: org.springframework.web.client.RestTemplate - Writing [
{code=[4/dVVrFDpNLDGTmXCuuQj6fcfaetEU.UkLPQd7NOLYbgrKXntQAax0INYiydQI],
redirect_uri=[http://localhost:8080/oauth/signin/google],
grant_type=[authorization_code]}] as "application/x-www-form-urlencoded"
This returns a code 400 ("bad request").
If I head over to hurl.it and POST the same data to the same URL (https://accounts.google.com/o/oauth2/token) and manually add in the client_id and client_secret values, the call returns a successful response.
So what could be causing the Google connector to omit these values?
For reference, I'm including the spring-social-google library in my project like:
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-google</artifactId>
<version>1.0.0.M1</version>
</dependency>
...and then in my #Configuration class I've got:
#Bean
#Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
public ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(
new GoogleConnectionFactory(
"<google client id>",
"<google secret key>"));
registry.addConnectionFactory(
new FacebookConnectionFactory(
"<facebook client id>",
"<facebook secret key>"));
registry.addConnectionFactory(
new TwitterConnectionFactory(
"<twitter client id>",
"<twitter secret key>"));
return registry;
}
The rest of what I'm using is pretty much standard straight out of the spring-social-showcase example (albeit hacked up to remove extraneous things and to work within the constraints noted above). Strangely, attempting to log in with Google does correctly show the OAuth authorization page on Google with my app/project name correctly displayed. The error happens after I hit the "Allow" button to authorize the OAuth login and return to the webapp.
Anyhow, what might be causing this issue, and how might it be fixed?
You may not have turned the google+ api on in the google developer console.
This is a separate task from getting an OAuth 2 token or api key.
If you have not done so already
http://console.developers.google.com
Navigate to your project.
Click 'APIs'.
Check 'Google+ API' is in the list of Enabled API's. If it is not, browse for it and enable it.
Related
I have gone through multiple blog posts and StackOverflow questions before writing my own. I have multiple queries and none of the posts answer them.
I am using Keycloak Spring Security Adapter to secure my legacy Spring application. I referred to the keycloak documentation here and was able to have OAuth flow running for me. I am using Client Id and Secret as Client Authenticator.
For eg: Access to localhost:8080/about.htm will redirect me to keycloak login screen and after successful authentication, I will be able to view my page. I am also using the below code to read the user details from the token,
KeycloakPrincipal<KeycloakSecurityContext> kp = (KeycloakPrincipal<KeycloakSecurityContext>) auth.getPrincipal();
IDToken idToken = kp.getKeycloakSecurityContext().getIdToken();
user.setUsername(idToken.getPreferredUsername());
Now when I test this application using postman and modify the generated access token, obviously the server gives an error. Ref : How to test application using postman.
However, this is the flow :
Client sends a request to the resource server, resource server checks for a token - if it exists, the client does the validation. If it doesn’t exist or is invalid, it redirects to the authorization server (KC).
My question is,
Who is validating this token? How does postman flow throw an error
if I fiddle with the token?
Do I really need to write a JwtTokenValidator in my application for
each request? Won't that be overkill?
If I use Client Authenticator as Signed Jwt with client secret, will this validation still be required? I am not using it as it introduces latency.
Please assist.
Answer to #1:
When you use any Keycloak adapters in your application (in your case the Spring adapter for Keycloak), that's the one who does the validation and redirects to the login if necessary. As part of the validation, it checks the signature of the token issued by Keycloak. So when you fiddle with the token, the signature doesn't match, hence it throws an error.
Answer to #2
No, you shouldn't need to implement a JwtTokenValidator. The adapter does it for you and a request should reach your endpoint/URL only if it has a valid token. You may only need to do that if you have a special requirements about validating the token (e.g. checking specific claim in the token against some service). Otherwise, you can safely use the claims in the token you received from the KeycloakSecurityContext. You can even setup authorization based on your URL patterns and Keycloak will enforce them too and allow the request to pass if user has necessary roles (like this example).
Answer to #3:
That option only changes the method used to authenticate your app to the Keycloak and has nothing to do with the user's token validation inside your app. In your current setup, when your app wants to communicate with Keycloak (e.g. to exchange auth code with auth token), it authenticate itself to Keycloak with a client-id/client-secret pair (otherwise Keycloak would not know it's your app and will reject the request).
If you choose the "Signed Jwt with Client Secret" option, your client can not just use a client-secret to authenticate to Keycloak. It should support the RFC7523 specification. So it's quite complex in compare with a simple clien-secret approach. In an environment in which you trust your clients (e.g. they're all known apps developed inside the company and you're not going to support public clients to join your Keycloak and use its services) it's quite common and safe to use client-secret approach.
I'm trying to develop a simple java client that needs to access Skype for Business APIs in order to setup an online meeting (i.e. I need to retrieve a simple setup meeting URL by invoking an UCWA API).
I followed this Microsoft tutorial step-by-step:
https://learn.microsoft.com/en-us/skype-sdk/ucwa/developingucwaapplicationsforsfbonline
I have an Office 365 Business Premium license and I configured a custom domain (correctly registered and added at the zone DNS file);
I configured and registered my java client app on Azure (taking care to assign required delegated permission for Skype for Business capabilities);
I performed the Sign-in phase and Azure is able to recognize me;
I performed the Autodiscovery phase in order to retrieve the user's UCWA home pool;
I sent a GET request to the Azure oauth2 endpoint with response 401 error (and this is the expected behaviour by the authentication handshake);
Unfortunately, I failed when I request an access token using implicit grant flow: Azure responds with a Sign-In HTML page rather than the json object containing the oauth2 access token.
What's wrong on this GET request?
GET https://login.microsoftonline.com/oauth2/authorize?
response_type=id_token
&client_id=my_application_client_id
&redirect_uri=configured_redirect_uri
&state=UUID_generated_code
&resource=UCWA_home_pool
HTTP/1.1
This GET URL looks like that one used for the Sign-In phase (step 3); I suspect that it isn't the right request URL.
I tryed to put my domain on the URL:
https://login.microsoftonline.com/my_domain_name/oauth2/authorize
and I tryed to put a common domain name (as reported on the documentation):
https://login.microsoftonline.com/common/oauth2/authorize
But Azure still reponds with a Sign-In page (and response code 200 OK).
Can someone help me please?
Please check the oauth2AllowImplicitFlow property in manifest of your application after downloading the latest manifest file. It should be set to true for this to wrok. If it's still false, only then I would expect the redirect to sign-in page as you're seeing.
More detailed steps here -
Configure your app for OAuth implicit grant flow
I have a web application that provides several rest services (Jersey). Most of the endpoints are secured by BASIC authentification. Further more I use SSL for transport and demand POSTs for every call.
The clients/consumers are android apps.
So far so good. The only service that seems to be vulnerable is the registration. It's the 'first' service to call and a user does not exist yet. So I cannot use OAuth, etc. I also have to keep the endpoint easy accessible to enable the user to regster.
How do I secure this service, so it's not spammed by a bot flooding my database?
How about these?
Use a registration link with a token in the request parameter. Ensure that the tokens expire after sometime. You could create a token endpoint url as well for a client to get a valid token.
Use a custom header or a dynamic custom header in your request. Additionally, you could check for a dynamic custom header to validate the request's authenticity.
Use registration confirmation workflows, such as an email / text verification as soon the registration is done. Run a process every day to delete any user accounts, which are not validated in say x days.
I do not think you can really secure the registration URL in a HTTP way. IMHO, anyone who has the registration url can be a right guy trying to register. So if you ask me, option 3 is better than others.
I use Cloud Endpoints and do client-side oauth to access my backend. This works fine, except that it means I can only check whether the person hitting up my app URL is a user or not after the whole page and attached scripts have loaded and the oauth request has completed.
I'd like to enable server-side authentication so that I can use the same URL for my landing page and my app, and redirect the person to the app if she is a user or to the landing page if she isn't.
The problem is that the User Tutorial uses the UserService for authentication whereas Cloud Endpoints uses the OAuth Service. I can't figure out how to use OAuth in my redirect filter because all the links from the OAuth section linked to above are for OAuth 1 and are deprecated.
How can I check in my redirect filter whether the person visiting is a user or not and simultaneously get a token that I can use to subsequently call my endpoints if she is a user?
I'm using the Google Api JS client to make calls to cloud endpoints, so the solution would optimally integrate with that, using gapi.auth.setToken(token) with the token retrieved and bypass the whole gapi.auth.authorize(params, callback) dance.
You can provide custom servlet implementaion for login flow where You will fetch oauth-token by providing new Flow and then validate that access token to grant authorization of protected resources.
Google provides good reference document here and You can use this sample code repo
for reference.
You can use the user API for endpoints, no need to use OAuth if doesn't suit your needs. You only need to add an parameter of the type com.google.appengine.api.users.User to your endpoint. As stated here.
Eg:
#ApiMethod(name = "scores.insert")
public Score insert(Score score, User user) throws OAuthRequestException, IOException {
//Check if user is null
//Do your thing
}
I am planing to write an API for a mobile app. To lower the barrier for first time users i do not want a login screen on the first start. So what I want is, if the app notices it is it's first start it should register itself:
/register
A standard User should be generated like Name: GuestXX43, Authtoken XX43-58asda5-54asd, some additional Data
The user is now able to make other endpoint request due to its auth token.
But how do I check for the correct auth token on every Request?
/user [Update]
the user is also able to update his username and password to reloggin on another Device.
Which auth method will suite these thoughts, is there any doubt using this kind of auth flow?
Thanks guys
Are you using Google Cloud Endpoints? If the user credentials is set in some header, you can retrieve it in the backend via injecting HttpServletRequest in Java or check HTTP_YOUR_HEADER_NAME environment variables in Python.
Also you can try custom authenticator if you uses Java; this post can be relevant: Google Cloud Endpoints and user's authentication.