I want to get email address using social plugin of grails . I am using facebook plugin compile ':spring-security-oauth-facebook:0.1' and configured properly in Config.groovy like below.
oauth {
debug = true
providers {
facebook {
api = org.scribe.builder.api.FacebookApi
key = 'here is my-key'
secret = 'my-secret-key'
successUri = '/oauth/facebook/success'
failureUri = '/oauth/facebook/failure'
callback = "${baseURL}/oauth/facebook/callback"
scopes = "email"
}
}
}
After get successfully response, below method is called.
def onSuccess(String provider) {
if (!provider) {
log.warn "The Spring Security OAuth callback URL must include the 'provider' URL
parameter"
throw new OAuthLoginException("The Spring Security OAuth callback URL must include the
'provider' URL parameter")
}
def sessionKey = oauthService.findSessionKeyForAccessToken(provider)
if (!session[sessionKey]) {
log.warn "No OAuth token in the session for provider '${provider}'"
throw new OAuthLoginException("Authentication error for provider '${provider}'")
}
}
OAuthToken oAuthToken = springSecurityOAuthService.createAuthToken(provider,
session[sessionKey])
println "oAuthToken.principal = "+oAuthToken.principal.toString();
println "oAuthToken.socialId = "+oAuthToken.socialId;
println "oAuthToken.properties= "+oAuthToken.properties
println "oAuthToken.properties= "+oAuthToken.name
println "oAuthToken.properties= "+oAuthToken.toString();
How to get email address by using this. I successfully get response from facebook but it is same number for Username,socialId,profileId but i need email Address like myemailid#gmail.com
please help me.
Related
I have successfully been able to get an access_token (or authenticationToken for Microsoft tokens) using the client side authentication in my Xamarin forms App. I am able to get further user information (email, name, etc.) using the same access token. Now, when I try to pass that token to my Azure Mobile Service backend, I get a 401 error.
Here is my code:
private async System.Threading.Tasks.Task<string> MSGetUserInfo(Account account)
{
// Reference: http://graph.microsoft.io/en-us/docs/overview/call_api
// Note that Microsoft don't recognize the access_token header entry, but rely instead on an Authorization header entry
var client = new HttpClient();
var userInfoRequest = new HttpRequestMessage()
{
RequestUri = new Uri("https://graph.microsoft.com/v1.0/me"),
Method = HttpMethod.Get,
};
// Add acccess Bearer
userInfoRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", account.Properties["access_token"]);
using (var response = await client.SendAsync(userInfoRequest).ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
Models.User user = new Models.User();
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var jobject = JObject.Parse(responseString);
var userName = (string)jobject["userPrincipalName"];
// Check username is valid
if (String.IsNullOrEmpty(userName))
{
throw new Exception("Username was not set for authenticated user");
}
else
user.ProviderLoginId = userName;
var userDisplayName = (string)jobject["displayName"];
// Replace display name if invalid
if (String.IsNullOrWhiteSpace(userDisplayName))
{
userDisplayName = userName;
}
else
user.Name = userDisplayName;
var userEmail = (string)jobject["mail"];
// Replace email if invalid
if (String.IsNullOrWhiteSpace(userEmail))
{
userEmail = userName;
}
else
user.Email = userEmail;
Valufy.App.currentUser = user;
}
else
{
throw new Exception("OAuth2 request failed: " + await response.Content.ReadAsStringAsync().ConfigureAwait(false));
}
}
return "success";
}
The above code snippet works in getting my user details. Now when I try to use the same token in the subsequent call, I get a 404:
public async Task<bool> Authenticate(string token)
{
string message = string.Empty;
var success = false;
JObject objToken = new JObject();
//objToken.Add("access_token", token); //for facebook and google
objToken.Add("authenticationToken", token); //for microsoft
try
{
// Sign in with Facebook login using a server-managed flow.
if (user == null)
{
//ProviderAuth("MICROSOFT");
user = await syncMgr.CurrentClient
.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount, objToken);
if (user != null)
{
success = true;
message = string.Format("You are now signed-in as {0}.", user.UserId);
}
}
}
catch (Exception ex)
{
message = string.Format("Authentication Failed: {0}", ex.Message);
}
// Display the success or failure message.
// await new MessageDialog(message, "Sign-in result").ShowAsync();
return success;
}
Is there something that I am doing wrong? Any and all assistance is appreciated.
According to your description, I followed this Git sample about Microsoft Graph Connect Sample for UWP (REST). I could get the access_token and it could work as expected with Microsoft Graph API (e.g. Get a user). But when I use this access_token as the authenticationToken token object for MobileServiceClient.LoginAsync, I could also get 401 Unauthorized.
Then I checked the managed client for Azure Mobile Apps about Authenticate users. For Client-managed authentication flow, I found that the official code sample about using Microsoft Account is working with Live SDK as follows:
// Request the authentication token from the Live authentication service.
// The wl.basic scope should always be requested. Other scopes can be added
LiveLoginResult result = await liveIdClient.LoginAsync(new string[] { "wl.basic" });
if (result.Status == LiveConnectSessionStatus.Connected)
{
session = result.Session;
// Get information about the logged-in user.
LiveConnectClient client = new LiveConnectClient(session);
LiveOperationResult meResult = await client.GetAsync("me");
// Use the Microsoft account auth token to sign in to App Service.
MobileServiceUser loginResult = await App.MobileService
.LoginWithMicrosoftAccountAsync(result.Session.AuthenticationToken);
}
Note: As LiveConnectSession states about AuthenticationToken:
The authentication token for a signed-in and connected user.
While check the authentication with Microsoft Graph, I could only find the access_token instead of AuthenticationToken.
UPDATE:
I have checked LiveLogin for WP8 and Microsoft Account Authentication for Mobile Apps via Fiddler to capture the authorize requests. I found that MS account authentication has the similar authorize request as Live SDK.
I assumed that you need to leverage Live SDK to authenticate the user when using client side authentication with Microsoft account. I found the Live SDK download page is not exist, you could follow the Live SDK for WP8 to get started with Live SDK.
UPDATE2:
For the client-flow authentication (Microsoft Account), you could leverage MobileServiceClient.LoginWithMicrosoftAccountAsync("{Live-SDK-session-authentication-token}"), also you could use LoginAsync with the token parameter of the value {"access_token":"{the_access_token}"} or {"authenticationToken":"{Live-SDK-session-authentication-token}"}. I have tested LoginAsync with the access_token from MSA and retrieve the logged info as follows:
I am using OAuth plugin for my Grails project for user to log in to my page. I am integrating facebook,google,and linkedIn to my web app. The OAuth plugin uses springSecurityOAuth plugin and respective OAuth plugins for facebook, google and linkedIn.
But the plugin is only fetching the userId from the social sites while I need to extract other profile info like firstname, lastname email etc. How can I achieve this?
I have already got required permissions for email and public_profile from facebook.
UPDATE:: I manually wrote code to get info such as firstname, lastname etc from providers. I am getting the required data from google but not from facebook. Am I doing any wrong here?
PS: I copied the same code from SpringSecurityOAuthService to get the info and made two for respective providers as shown:
def getUserDetailsGoogle(googleAccessToken){
if (provider=='google'){
def response = oauthService.getGoogleResource(googleAccessToken, 'https://www.googleapis.com/oauth2/v1/userinfo')
def googleResponse
try {
googleResponse = JSON.parse(response.body)
} catch (Exception e) {
log.error "Error parsing response from Google. Response:\n${response.body}"
throw new OAuthLoginException('Error parsing response from Google', e)
}
return googleResponse
}
}
def getUserDetailsFacebook(facebookAccessToken){
def response = oauthService.getFacebookResource(accessToken, 'https://graph.facebook.com/me')
def user
try {
facebookResponse = JSON.parse(response.getBody())
} catch (Exception e) {
log.error "Error parsing response from Facebook. Response:\n${response.body}"
throw new OAuthLoginException("Error parsing response from Facebook", e)
}
if (! facebookResponse?.id) {
log.error "No user id from Facebook. Response:\n${response.body}"
throw new OAuthLoginException("No user id from Facebook")
}
return facebookResponse
}
In my Grails 2.5.X app I use pac4j for authenticating with Facebook, Google, etc. by adding these dependencies to BuildConfig.groovy
dependencies {
compile 'org.pac4j:pac4j-core:1.6.0',
compile 'org.pac4j:pac4j-oauth:1.6.0'
}
The relevant controller class is shown below. If you want to look at the source of the OauthService it calls (or anything else), check out the GitHub repository I've linked to.
#Secured(['permitAll'])
class OauthController {
OauthService oauthService
GrailsApplication grailsApplication
SpringSecurityService springSecurityService
UserRegistrationService userRegistrationService
/**
* Starts the OAuth authentication flow, redirecting to the provider's Login URL. An optional callback parameter
* allows the frontend application to define the frontend callback URL on demand.
*/
def authenticate(String provider) {
BaseOAuthClient client = oauthService.getClient(provider)
WebContext context = new J2EContext(request, response)
RedirectAction redirectAction = client.getRedirectAction(context, true, false)
log.debug "Redirecting to ${redirectAction.location}"
redirect url: redirectAction.location
}
/**
* Handles the OAuth provider callback.
*/
def callback(String provider, String error) {
WebContext context = new J2EContext(request, response)
if (!error) {
try {
CommonProfile profile = oauthService.getUserProfile(provider, context)
User registeredUser = userRegistrationService.socialSignIn(profile, provider)
if (!registeredUser.isAttached()) {
// User is trying to register with an OAuth provider (e.g. Twitter, Yahoo), that doesn't provide their
// email address so they need to submit a form to supply us with their email
render view: '/register/confirmEmail', model: [user: registeredUser]
return
}
springSecurityService.reauthenticate(registeredUser.username)
flashHelper.info 'social.login.success': provider
redirect uri: '/'
return
} catch (ex) {
log.error "Error occurred during callback from OAuth2 provider '$provider'", ex
}
} else {
// Most likely explanation is that the user denied access on the consent screen which is not really an error
log.warn "Callback from OAuth2 provider '$provider' failed due to error: $error"
}
flashHelper.warn 'social.login.fail'
redirect uri: '/'
}
}
I am using Postman to test OAuth 2 from a vanilla AEM install.
Postman can successfully obtain the authorization code from /oauth/authorize after I grant access:
But when it tries to use the code to obtain a token from /oauth/token it receives the following response:
HTTP ERROR: 403 Problem accessing /oauth/token. Reason: Forbidden
Powered by Jetty://
Looking in Fiddler it is doing a POST to /oauth/token with the following Name/Values in the body:
client_id: Client ID from /libs/granite/oauth/content/client.html
client_secret:
Client Secret from /libs/granite/oauth/content/client.html
redirect_uri: https://www.getpostman.com/oauth2/callback
grant_type: authorization_code
code: Code returned from previous request to oauth/authorize
Am I missing something?
Would help if you can list some code snippets on how you are building the url and fetching the token.
Here's an example of how we've implemented very similar to what you are trying to do, maybe it'll help.
Define a service like below (snippet) and define the values (host, url, etc) in OSGI (or you can also hard code them for testing purposes)
#Service(value = OauthAuthentication.class)
#Component(immediate = true, label = "My Oauth Authentication", description = "My Oauth Authentication", policy = ConfigurationPolicy.REQUIRE, metatype = true)
#Properties({
#Property(name = Constants.SERVICE_VENDOR, value = "ABC"),
#Property(name = "service.oauth.host", value = "", label = "Oauth Host", description = "Oauth Athentication Server"),
#Property(name = "service.oauth.url", value = "/service/oauth/token", label = "Oauth URL", description = "Oauth Authentication URL relative to the host"),
#Property(name = "service.oauth.clientid", value = "", label = "Oauth Client ID", description = "Oauth client ID to use in the authentication procedure"),
#Property(name = "service.oauth.clientsecret", value = "", label = "Oauth Client Secret", description = "Oauth client secret to use in the authentication procedure"),
#Property(name = "service.oauth.granttype", value = "", label = "Oauth Grant Type", description = "Oauth grant type") })
public class OauthAuthentication {
...
#Activate
private void activate(ComponentContext context) {
Dictionary<String, Object> properties = context.getProperties();
host = OsgiUtil.toString(properties, PROPERTY_SERVICE_OAUTH_HOST,new String());
// Similarly get all values
url =
clientID =
clientSecret =
grantType =
authType = "Basic" + " "+ Base64.encode(new String(clientID + ":" + clientSecret));
}
public static void getAuthorizationToken(
try {
UserManager userManager = resourceResolver.adaptTo(UserManager.class);
Session session = resourceResolver.adaptTo(Session.class);
// Getting the current user
Authorizable auth = userManager.getAuthorizable(session.getUserID());
user = auth.getID();
password = ...
...
...
String serviceURL = (host.startsWith("http") ? "": protocol + "://") + host + url;
httpclient = HttpClients.custom().build();
HttpPost httppost = new HttpPost(serviceURL);
// set params
ArrayList<BasicNameValuePair> formparams = new ArrayList<BasicNameValuePair>();
formparams.add(new BasicNameValuePair("username", user));
formparams.add(new BasicNameValuePair("password", password));
formparams.add(new BasicNameValuePair("client_id", clientID));
formparams.add(new BasicNameValuePair("client_secret",clientSecret));
formparams.add(new BasicNameValuePair("grant_type",grantType));
UrlEncodedFormEntity postEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
httppost.setEntity(postEntity);
// set header
httppost.addHeader("Authorization", authType);
response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (response.getStatusLine().getStatusCode() == 200) {
if (entity != null) {
object = new JSONObject(EntityUtils.toString(entity));
}
if (object != null) {
accessToken = object.getString("access_token");
////
}
}
}
I found the answer myself and thought I'd share the process I went through as well as the answer because it might help other people new to AEM.
How to find the cause of the error:
Go to CRXDE Lite.
Select console.
Then deselect the stop button to allow new console logs to appear (this is very counter-intuitive to me).
From here I was able to see the cause of the issue:
org.apache.sling.security.impl.ReferrerFilter Rejected empty referrer header for POST request to /oauth/token
Because postman does not place a referrer in the request header I had to tell Apache Sling to allow empty request headers.
To do this:
Go to /system/console/configMgr
Open the Apache Sling Referrer Filter Config
Select the Allow Empty check box
Good way to allow this to list the allowed hosts, otherwise this is against best practices for AEM security checklist.
Its fine for development environment not for production.
I've the the latest version of Linq to Twitter (3.1.2), and I'm receiving the "Bad Authentication data" error with the code below:
var auth = new ApplicationOnlyAuthorizer
{
CredentialStore = new InMemoryCredentialStore
{
ConsumerKey = "xxxx",
ConsumerSecret = "xxxx"
}
};
using (var twitter = new TwitterContext(auth))
{
var users = twitter.User.Where(s => s.Type == UserType.Search && s.Query == "filter:verified").ToList();
}
I thought at first that it could be Twitter taking a while to accept my new credentials, but I used Twitter's OAuth tool with my keys, and they produced tokens without issue. Any ideas what I'm missing here?
I could not find a duplicate, as the code referenced # https://stackoverflow.com/questions/16387037/twitter-api-application-only-authentication-with-linq2twitter#= is no longer valid in the version I am running.
That query doesn't support Application-Only authorization. Here's the Twitter docs to that:
https://dev.twitter.com/rest/reference/get/users/search
Instead, you can use SingleUserAuthorizer, documented here:
https://github.com/JoeMayo/LinqToTwitter/wiki/Single-User-Authorization
Like this:
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"],
AccessToken = ConfigurationManager.AppSettings["accessToken"],
AccessTokenSecret = ConfigurationManager.AppSettings["accessTokenSecret"]
}
};
To find out what type of authorization is possible, you can visit the L2T wiki at:
https://github.com/JoeMayo/LinqToTwitter/wiki
and each API query and command has a link at the bottom of the page to the corresponding Twitter API documentation.
Its a grails project,
Facebook authentication is successful via oauth,
Now when it comes back to my controller, I want to get emailID of the logged in user,
Searched a lot, but did not find proper documentation,
I am using scribe and have following code in Config.groory
import org.scribe.builder.api.FacebookApi
oauth {
providers {
facebook {
api = FacebookApi
key = 'xxxx'
secret = 'yyyy'
callback = "http://my-domain-name-here:8080/TestOAuth2/dashBoard/facebooklogin"
successUri = "http://my-domain-name-here:8080/TestOAuth2/dashBoard/success"
}
}
}
Any help much appreciated.
Thanks.
Try this..,.
Config:
import org.scribe.builder.api.FacebookApi
...
oauth {
providers {
facebook {
api = FacebookApi
key = 'XXX'
secret = 'YYY'
scope = 'email,read_stream,publish_actions,user_birthday,publish_stream'
callback = "http://localhost:8080/appName/oauth/facebook/callback" //callback to oauth controller of oauth plugin
successUri = "http://localhost:8080/appName/myController/facebookSuccess"
failureUri = "http://localhost:8080/appName/myController/facebookFailure"
}
}
}
MyController:
def facebookSuccess() {
Token facebookAccessToken = (Token) session[oauthService.findSessionKeyForAccessToken('facebook')]
def facebookResource = oauthService.getFacebookResource(facebookAccessToken, "https://graph.facebook.com/me")
def facebookResponse = JSON.parse(facebookResource?.getBody())
log.info "Email = ${facebookResponse.email}"
...
}
You can get working example from my git repo. Grails Oauth Plugin Demo.
Email is not part of a Facebook public_profile. The only way to get the users e-mail address is to request extended permissions on the email field. You can do this by adding a scope to the oauth provider.
config.groovy
oauth {
providers {
facebook {
api = org.scribe.builder.api.FacebookApi
scope = 'email'
...
...
}
}
}
As an example of how to return email and various public_profile fields please see below.
Take Note of: getFacebookResource params e.g. https://graph.facebook.com/me?fields=id,name,verified,age_range,email"
import grails.converters.JSON
import org.scribe.model.Token
import grails.plugin.springsecurity.oauth.OAuthToken
class SpringSecurityOAuthController {
def oauthService
def onSuccess = {
// Validate the 'provider' URL. Any errors here are either misconfiguration
// or web crawlers (or malicious users).
if (!params.provider) {
renderError 400, "The Spring Security OAuth callback URL must include the 'provider' URL parameter."
return
}
def sessionKey = oauthService.findSessionKeyForAccessToken(params.provider)
if (!session[sessionKey]) {
renderError 500, "No OAuth token in the session for provider '${params.provider}'!"
return
}
// Create the relevant authentication token and attempt to log in.
OAuthToken oAuthToken = createAuthToken(params.provider, session[sessionKey])
Token facebookAccessToken = (Token) session[oauthService.findSessionKeyForAccessToken('facebook')]
def facebookResource = oauthService.getFacebookResource(facebookAccessToken , "https://graph.facebook.com/me?fields=id,name,verified,age_range,email")
def facebookResponse = JSON.parse(facebookResource?.getBody())
println facebookResponse
...
...
}
}
public_profile (Default)
A person's public profile refers to the following properties on the user object by default:
id cover
name
first_name
last_name
age_range
link
gender
locale
picture
timezone
updated_time
verified