Get facebook access token with spring social FacebookConnectionFactory - java

I am trying to implement a Facebook Connection using Spring Social, based on this example(from spring social manual):
FacebookConnectionFactory connectionFactory =
new FacebookConnectionFactory("clientId", "clientSecret");
OAuth2Operations oauthOperations = connectionFactory.getOAuthOperations();
OAuth2Parameters params = new OAuth2Parameters();
params.setRedirectUri("https://my-callback-url");
String authorizeUrl = oauthOperations.buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
response.sendRedirect(authorizeUrl);
// upon receiving the callback from the provider:
AccessGrant accessGrant = oauthOperations.exchangeForAccess(authorizationCode, "https://my-callback-url", null);
Connection<Facebook> connection = connectionFactory.createConnection(accessGrant);
My problem is that I don't know what my redirect url should be.My code is this:
#RequestMapping("/face")
public String communicate() {
FacebookConnectionFactory connectionFactory =
new FacebookConnectionFactory(clientId, clientSecret);
OAuth2Operations oauthOperations = connectionFactory.getOAuthOperations();
OAuth2Parameters params = new OAuth2Parameters();
//this remdirectUri should be another one?
params.setRedirectUri("http://dev01.spring:8080/spring/face");
String authorizeUrl = oauthOperations.buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
System.out.println(authorizeUrl);
//return "redirect:"+authorizeUrl;
// upon receiving the callback from the provider:
//AccessGrant accessGrant = oauthOperations.exchangeForAccess(authorizationCode, "https://my-callback-url", null);
//Connection<Facebook> connection = connectionFactory.createConnection(accessGrant);
}
My authorizeUrl is like this(from System.out line):
https://graph.facebook.com/oauth/authorize?client_id=myId&response_type=code&redirect_uri=http%3A%2F%2Fdev01.spring%3A8080%2Fspring%2Fface
If i uncomment the line where I continue the Oauth flow redirecting to this authorizeUrl, i'm getting the following error: This webpage has a redirect loop.
So my question is, what the redirect uri should be.Thank you.
Very late edit, in the hopes it helps someone. This is my controller and the method that does the whole Oauth2 dance. I must add that this worked when the question was asked, I have no idea how it behaves now.
#Controller
public class FacebookController {
private static final String clientId = "clientIdHere"; // clientId from facebook app
private static final String clientSecret = "clientSecret here"; // clientSecret
private FacebookConnectionFactory connectionFactory; // facebookConnectionFactory
/*
* If an authorization was given by provider(code) we get an token and bind the api.
*/
#RequestMapping("/facebook/callback")
public String authorize(#RequestParam("code") String authorizationCode,Model model) {
// exchange facebook code with an access token.
AccessGrant accessGrant = connectionFactory.getOAuthOperations().exchangeForAccess(authorizationCode, "http://localhost:8080/testApp/facebook/callback", null); // not that the application was deployed at "http://localhost:8080/testApp"
// connect to facebook with the given token.
Connection<Facebook> connection = connectionFactory.createConnection(accessGrant);
// bind the api
Facebook facebook = connection.getApi();
// get user profile informations
FacebookProfile userProfile = facebook.userOperations().getUserProfile();
// At this point you have acces to the facebook api.
// For ex you can get data about the user profile like this
// create user with facebook's user accounts details.
User facebookUser = new User(userProfile.getFirstName(),
userProfile.getLastName(),
userProfile.getEmail(),
Role.ROLE_FACEBOOKUSER,
"socialuser");
return "redirect:/home";
}
}

Related

Generating authentication token for APNS connection

I am new to vertx, and using an app server created via vertx for connection with APNS for push notifications.
I created an authProvider via
private JWTAuth createOauthProvider() {
PubSecKeyOptions pubSecKeyOptions = new PubSecKeyOptions()
.setAlgorithm("ES256").setSecretKey(*/private key from .p8 extracted as is removing unwanted part in base64*/);
return JWTAuth.create(vertx(), new JWTAuthOptions().addPubSecKey(pubSecKeyOptions));
}
and then a JWT via
private String createJwt() {
Instant now = Instant.now();
JsonObject decoded = new JsonObject()
.put("alg", "ES256")
.put("kid", "kid here")
.put("iss", "teamid here")
.put("iat", now.getEpochSecond());
String jwt = oauth2JWTProvider.generateToken(decoded,
new JWTOptions().setAlgorithm("ES256"));
return jwt;
}
Now here's my query -
Is my token creation criteria correct?
JWT created after this when send to APNS returns a 403-InvalidProviderToken.
Appreciate all the help i can get. Thanks!!
Answering my own question as i was able to get around this and just in case it helps anyone else. Just posting the createJwt() method rest everything remains same-
private String createJwt() {
Instant now = Instant.now();
JsonObject header = new JsonObject()
.put(JwtConstants.ALG, "ES256")
.put(JwtConstants.KID, "kid here");
JsonObject payload = new JsonObject()
.put(JwtConstants.ISS, "team id here")
.put(JwtConstants.IAT, now.getEpochSecond());
String jwt = oauth2JWTProvider.generateToken(payload,
new JWTOptions()
.setHeader(header)
.setAlgorithm("ES256"));
return jwt;
}

Retrieve all Managed Devices using Java (with Microsoft Graph API SDK)

I would like to retrieve all devices managed by Intune (managed devices) using the Microsoft Graph Java SDK. I have created the app in Microsoft Azure and given the appropriate API permissions:
API Permissions
The following code creates a graphClient object and a method that retrieves all managed devices.
#Service
public class AzureServiceDefault implements AzureService
{
private static final String CLIENT_ID = "XXXXXXXXXXXXXXXXXXXXXXXX";
private static final List<String> SCOPES = Arrays.asList(new String[]{"https://graph.microsoft.com/.default"});
private static final String TENANT = "XXXXXXXXXXXXXXXXXXXXXXXX";
private static final String CLIENT_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXX";
ClientCredentialProvider authProvider = new ClientCredentialProvider(CLIENT_ID, SCOPES, CLIENT_SECRET, TENANT, NationalCloud.Global);
IGraphServiceClient graphClient;
public AzureServiceDefault()
{
graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
}
#Override
public List<IntuneDevice> getManagedDevices()
{
IManagedDeviceCollectionRequestBuilder managedDeviceRequestBuilder;
IDeviceManagementRequestBuilder builder = graphClient.deviceManagement();
IDeviceManagementRequest managedDevicesRequest = builder.buildRequest();
List<ManagedDevice> managedDevices = new ArrayList<>();
List<IntuneDevice> allManagedDevices = new ArrayList<>();
do {
try {
DeviceManagement deviceManagement = managedDevicesRequest.get();
ManagedDeviceCollectionPage managedDevicesCollectionPage = deviceManagement.managedDevices;
//Process items in the response
managedDevices.addAll(managedDevicesCollectionPage.getCurrentPage());
managedDevices.stream().forEach((device) -> allManagedDevices.add(new IntuneDevice(device.id,
device.userId,
device.deviceName,
device.managedDeviceOwnerType.toString(),
device.operatingSystem,
device.osVersion,
device.complianceState.toString(),
device.azureADRegistered,
device.azureADDeviceId,
device.userPrincipalName,
device.model,
device.manufacturer,
device.serialNumber)));
//Build the request for the next page, if there is one
managedDeviceRequestBuilder = managedDevicesCollectionPage.getNextPage();
if (managedDeviceRequestBuilder == null)
{
managedDevicesRequest = null;
}
else
{
managedDevicesRequest = (IDeviceManagementRequest) managedDeviceRequestBuilder.buildRequest();
}
}
catch(ClientException ex)
{
ex.printStackTrace();
managedDevicesRequest = null;
}
} while (managedDevicesRequest != null);
return allManagedDevices;
}
}
The problem is that the variable managedDevices turns out to be null and this is the error message:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/] threw exception [Request processing failed; nested exception is java.lang.NullPointerException: Cannot invoke "com.microsoft.graph.requests.extensions.ManagedDeviceCollectionPage.getCurrentPage()" because "managedDevicesCollectionPage" is null] with root cause
java.lang.NullPointerException: Cannot invoke "com.microsoft.graph.requests.extensions.ManagedDeviceCollectionPage.getCurrentPage()" because "managedDevicesCollectionPage" is null
What do I need to change to make this code work? I am succesfully able to retrieve all users in Azure AD, but I am having difficulties getting data from Intune/Endpoint Manager. Do I need to make changes to the SCOPES?
It should be possible to retrieve all managed devices as the REST API for it is https://graph.microsoft.com/v1.0/deviceManagement/managedDevices
Thanks for your help
This MS Graph API does not support application permissions, so you couldn't list managedDevices with ClientCredentialProvider. ClientCredentialProvider is based on client credential flow that requires application permission.
You could use AuthorizationCodeProvider to get the list. And follow this to get AUTHORIZATION_CODE first.
String CLIENT_ID = "xxxxxx";
List<String> SCOPES = Arrays.asList(new String[] { "https://graph.microsoft.com/.default" });
String CLIENT_SECRET = "xxxxxx";
String TENANT = "xxxxxx";
String AUTHORIZATION_CODE = "";
String REDIRECT_URL = "xxxxxx";
AuthorizationCodeProvider authProvider = new AuthorizationCodeProvider(CLIENT_ID, SCOPES, AUTHORIZATION_CODE,
REDIRECT_URL, NationalCloud.Global, TENANT, CLIENT_SECRET);
IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
IManagedDeviceCollectionPage managedDeviceCollectionPage = graphClient.deviceManagement().managedDevices().buildRequest().get();
List<ManagedDevice> managedDeviceList = managedDeviceCollectionPage.getCurrentPage();

How do you authenticate to Cisco Contact Center Express Identity Service?

I'm building a 3rd party app to authenticate with Contact Center Express. The documentation is necessary, but insufficient to accomplish this. For example,
https://developer.cisco.com/docs/contact-center-express/#!cisco-identity-service-client-sdk-guide/during-agent-login
// Get Access Token for the received Authorization Code
String redirectURI = config.getRedirectUri();
AccessToken token = client.getAccessToken(authCode, redirectURI);
When and where do you redirect the user to Contact Center to authenticate? I observed that Finesse will redirect the user to
https://contactcenter.example.com:8553/ids/v1/oauth/authorize?redirect_uri=https%3A%2F%2Ffinesse.example.com%3A443%2Fdesktop%2Fsso%2Fauthcode&client_id=8a75xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&state=aHR0cHM6Ly92bS1mLWZpbi1hLmRldi5pbi5zcGluc2NpLmNvbS9kZXNrdG9wL2pfaWRlbnRpdHlfY2hlY2s%2FZXJyb3I9dHJ1ZQlhcHBsb2dpbg%3D%3D&response_type=code
But where is it specified to use the identity service (IDS) path /ids/v1/oauth/authorize? And is state a required parameter? And does the IDS SDK handle the callback path /desktop/sso/authcode? I imagine that it doesn't but what are the parameters that will be sent to it? I'm using Spring framework.
Am I to reverse engineer the whole process, or is there additional documentation that I am missing?
Even after I receive an OAuth token, how would I use it to make other REST calls to other Cisco products? The Finesse REST APIs only mention HTTP basic authentication. There is no mention of headers for "Authorization: Bearer" tokens.
https://developer.cisco.com/docs/finesse/#!sign-in-to-finesse/sign-in-to-finesse
I had to reverse engineer it following all the redirects.
#Controller
public class SSOController {
#Autowired
private IdSClientConfigurationImpl config;
#Autowired
private IdSClient client;
#PostMapping("/login")
public String login(#RequestParam(name="user", required=true) String user) {
// redirect the user to the Cisco Contact Center Express Identity Service
String redirectURI = config.getRedirectUri();
String clientId = config.getClientId();
URI uri = UriComponentsBuilder
.fromUriString("https://contact-center-express:8553/ids/v1/oauth/authorize")
.queryParam("redirect_uri", "{redirect_uri}")
.queryParam("client_id", "{client_id}")
// .queryParam("state", "{state}") // base64 encoded
.queryParam("response_type", "code")
.build(redirectURI, clientId);
return "redirect:"+uri.toString();
}
#GetMapping("/idscallback")
public String idscallback(
#RequestParam(name="code", required=true) String code,
#RequestParam(name="state", required=false) String state,
HttpSession session) throws IdSClientException {
// Get Access Token for the received Authorization Code
String redirectURI = config.getRedirectUri();
AccessToken token = client.getAccessToken(code, redirectURI); // why do I need redirectURI when it's already redirected?
String accessTokenString = token.getAccess_token();
session.setAttribute("token", accessTokenString);
// model.addAttribute("token", accessTokenString);
return "redirect:/";
}
And in a bean far, far away...
#Bean
public IdSClientConfigurationImpl config() throws IOException, IdSClientException {
ClassPathResource idsclientResource = new ClassPathResource("idsclient.properties");
IdSClientConfigurationImpl config = new IdSClientConfigurationImpl(idsclientResource.getFile().getPath());
// IdSClientConfigurationImpl config = new IdSClientConfigurationImpl("src/main/resources/idsclient.properties");
config.load();
return config;
}
#Bean
public IdSClient setupIdsClient() throws IOException, IdSClientException {
IdSClient client = IdSClientFactory.getIdSClient();
client.setTLSContext(createSSLTrustManager(), createHostnameVerifier());
// client.setTLSContext(arg0, arg1) // use secure trust manager and hostname verifier in production
client.init(config);
return client;
}
private X509TrustManager createSSLTrustManager() {
X509TrustManager tm = new TrustAllX509TrustManager();
return tm;
}
private HostnameVerifier createHostnameVerifier() {
HostnameVerifier hv = new SkipAllHostNameVerifier();
return hv;
}

How to login to facebook using Facebook4j

I am developing a photo viewer, which is a java desktop application and to integrate it with facebook I am using the Facebook4J library.
But I am clueless as to where to provide the username and password for the user....
I am using the following code :
public static Configuration createConfiguration() {
ConfigurationBuilder confBuilder = new ConfigurationBuilder();
confBuilder.setDebugEnabled(true);
confBuilder.setOAuthAppId("************");
confBuilder.setOAuthAppSecret("***************");
confBuilder.setUseSSL(true);
confBuilder.setJSONStoreEnabled(true);
Configuration configuration = confBuilder.build();
return configuration;
}
public static void main(String[] argv) throws FacebookException {
Configuration configuration = createConfiguration();
FacebookFactory facebookFactory = new FacebookFactory(configuration );
Facebook facebookClient = facebookFactory.getInstance();
AccessToken accessToken = null;
try{
OAuthSupport oAuthSupport = new OAuthAuthorization(configuration );
accessToken = oAuthSupport.getOAuthAppAccessToken();
}catch (FacebookException e) {
System.err.println("Error while creating access token " + e.getLocalizedMessage());
}
facebookClient.setOAuthAccessToken(accessToken);
//results in an error says {An active access token must be used to query information about the current user}
facebookClient.postStatusMessage("Hello World from Facebook4J.");
}
How to pass the username and password the user?
You should retrieve an OAuthAppId from facebook. To do this, create an App on Facebook Developers and click "Create new app". Fill in the form, then copy paste the AppId and Appsecret from the page that appears in your code. Example:
confBuilder.setOAuthAppId("YOUR APPID HERE");
confBuilder.setOAuthAppSecret("YOUR APPSECRET HERE");
To get the AccessToken, you have to build a login flow as described here

Spring Security & Facebook OAuth 2.0 Integration with Graph API

Please, at least pseudo (but from working environment not "maybe this should work") application context and controller/filter that will authenticate and/or auto-register Facebook users.
This link: http://blog.kadirpekel.com/2009/11/09/facebook-connect-integration-with-spring-security/ will not do. Actually I will put minus point to anyone who will post it as answer. I spend 2 hours with the thing and I didn't get it to work. I ended bit more bolder and feeling more stupid than usual after this endeavor :-(
I would really like to see OAuth 2.0 solution for facebook connect. And restrict the use of Facebook JavaScript API to absolute minimum.
Following link shows about what I need:
http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/
Please post only code to this question. I already got all the advice I can handle.
UPDATE
I have servlet solution and posted answer here if anyone is interested:
Facebook Connect example in JSP (tomcat)
Here's an MVC implementation of facebook OAuth 2.0
The code's in C# and hopefully its similarity with java helps you out.
Controller(Entry point):Controller(in MVC) is the point in the code where the control reaches after someone clicks on the login link.
public ActionResult Authenticate()
{
var oauthFacebook = new FacebookOAuth();
if (Request["code"] == null)
{
//Redirect the user to Facebook for authorization.
Response.Redirect(oauthFacebook.AuthorizationLinkGet());
}
else
{
//Get the access token and secret.
oauthFacebook.AccessTokenGet(Request["code"]);
if (oauthFacebook.Token.Length > 0)
{
//We can now make our api calls
var user = oauthFacebook.GetAttributes();
}
}
}
FacebookOAuth Class
public class FacebookOAuth : Oauth
{
public FacebookOAuth()
{
Authorize = "https://graph.facebook.com/oauth/authorize";
AccessToken = "https://graph.facebook.com/oauth/access_token";
CallbackUrl = "http://<YourURLHere>/Authenticate";
AttributesBaseUrl = "https://graph.facebook.com/me/?access_token=";
ConsumerKey = ConfigurationManager.AppSettings["FacebookConsumerKey"];//Ur Consumer Key goes here
ConsumerSecret = ConfigurationManager.AppSettings["FacebookConsumerSecret"];//Ur Consumer secret goes here
Provider = "Facebook";
}
public override string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=email,user_education_history,user_location,user_hometown",
Authorize, ConsumerKey, CallbackUrl);
}
public User GetAttributes()
{
string attributesUrl = string.Format("{0}{1}", AttributesBaseUrl, Token);
string attributes = WebRequest(Method.Get, attributesUrl, String.Empty);
var FacebookUser = new JavaScriptSerializer().Deserialize<FacebookUser>(attributes);
return new User()
{
FirstName = FacebookUser.first_name,
MiddleName = FacebookUser.middle_name,
LastName = FacebookUser.last_name,
Locale = FacebookUser.locale,
UserEmail = FacebookUser.email,
AuthProvider = Provider,
AuthToken=Token
};
}
}
OAuth baseclass(Class from which FacebookOAuth derives)
public abstract class Oauth
{
#region Method enum
public enum Method
{
Get,
Post,
Delete
} ;
#endregion
protected string AccessToken;
protected string AttributesBaseUrl;
protected string Authorize;
protected string CallbackUrl;
protected string ConsumerKey;
protected string ConsumerSecret;
public string Provider { get; protected set; }
public string Token { get; set; }
public virtual string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=publish_stream,email,user_education_history,user_location",
Authorize, ConsumerKey, CallbackUrl);
}
public void AccessTokenGet(string authToken)
{
Token = authToken;
string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
AccessToken, ConsumerKey, CallbackUrl, ConsumerSecret, authToken);
string response = WebRequest(Method.Get, accessTokenUrl, String.Empty);
if (response.Length > 0)
{
//Store the returned access_token
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["access_token"] != null)
{
Token = qs["access_token"];
}
}
}
public string WebRequest(Method method, string url, string postData)
{
StreamWriter requestWriter;
string responseData = string.Empty;
var webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
if (webRequest != null)
{
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false;
webRequest.Timeout = 20000;
if (method == Method.Post)
{
webRequest.ContentType = "application/x-www-form-urlencoded";
//POST the data.
requestWriter = new StreamWriter(webRequest.GetRequestStream());
try
{
requestWriter.Write(postData);
}
finally
{
requestWriter.Close();
}
}
responseData = WebResponseGet(webRequest);
}
return responseData;
}
public string WebResponseGet(HttpWebRequest webRequest)
{
StreamReader responseReader = null;
string responseData;
try
{
responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
responseData = responseReader.ReadToEnd();
}
finally
{
if (webRequest != null) webRequest.GetResponse().GetResponseStream().Close();
if (responseReader != null) responseReader.Close();
}
return responseData;
}
}
I actually just finished my non-javascript, implementation of the Facebook Graph API Authentication last night. I was a gargantuan pain in the a**, but it works and it's working fairly well.
I used the example from the link you posted above as a starting point, as well as, the code from here as a starting point. I had to write my own implementation of their FacebookGraphAuthenticationProvider and their FacebookGraphAuthenticationFilter, but now it works the way I want it to.
You need to create implementations of both of these files, put your filter in the filter chain, and create a implementation of the Spring Security UserDetailsService that the Provider can use to manage your user account information. I have some code on my machine at home that I can send you via email if you like.
Here are the steps I had to use to get the authentication to work:
Get an "code" for a user, this is done by making the following call: https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream (The scope is all the permissions you want to request from FB). This call will create an "authentication code" which will then be sent back to your "redirect_uri" (which I stated as http://{my fb app registered domain}/j_spring_security_authentication_check.
Once you have this "code", you need to make a call within your AuthenticationProvider that will retrieve an access_token for your user's session: this URL looks like: https://graph.facebook.com/oauth/access_token? client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE. You have to make sure your "redirect_uri" is the same as the one you did in #1. You'll make the above call using something like Apache's HttpClient, or the like.
Now with this access_token (which comes in the body of above response), you can get your user's profile information with the following URL: https://graph.facebook.com/me?access_token={ACCESS_TOKEN from above). The response will be in JSON. You can also use the access_token with all of the graph API to post status, pictures, etc.
I have some code at home that has my full implementation that I would be happy to share.
I hope this helps at least a bit. I suggest using the Spring Social app to get started with posting status, pictures, wall stuff, etc. This will be a good place to start looking at FB-Spring interaction.

Categories

Resources