everything in place for oAuth, just need to parse XML
git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/user/social-profile@99408 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
462549bf9b
commit
1069bf8229
9
pom.xml
9
pom.xml
|
@ -66,6 +66,10 @@
|
|||
<artifactId>custom-portal-handler</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.json-simple</groupId>
|
||||
<artifactId>json-simple</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.gcube.applicationsupportlayer</groupId>
|
||||
<artifactId>aslcore</artifactId>
|
||||
|
@ -93,6 +97,11 @@
|
|||
<version>[2.13.0-SNAPSHOT, 3.0.0-SNAPSHOT)</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.liferay.portal</groupId>
|
||||
<artifactId>portal-service</artifactId>
|
||||
|
|
|
@ -10,8 +10,10 @@ import org.gcube.portlets.user.socialprofile.shared.UserContext;
|
|||
|
||||
import com.google.gwt.core.client.EntryPoint;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.user.client.Cookies;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
|
||||
|
@ -27,8 +29,37 @@ public class SocialProfile implements EntryPoint {
|
|||
|
||||
public void onModuleLoad() {
|
||||
if (isUserAuthZFromLinkedIn()) {
|
||||
checkLinkedInAuthZ();
|
||||
String authorizationCode = checkLinkedInAuthZ();
|
||||
if (authorizationCode != null) {
|
||||
mainPanel.add(new OkAlert("Authorization OK! Please wait while we import from LinkedIn ... "));
|
||||
socialService.fetchUserProfile(authorizationCode, DisplayProfile.getRedirectURI(), new AsyncCallback<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
if (!result) {
|
||||
mainPanel.clear();
|
||||
mainPanel.add(new ErrorAlert("Something went wrong while parsing your professional summary from LinkedIn, please report the issue."));
|
||||
}
|
||||
else
|
||||
Window.alert("funzia!");
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
mainPanel.clear();
|
||||
mainPanel.add(new ErrorAlert("Something went wrong while communicating with LinkedIn service, please report us the issue."));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
} else {
|
||||
displayProfile();
|
||||
}
|
||||
|
||||
RootPanel.get("SocialProfileDiv").add(mainPanel);
|
||||
}
|
||||
/**
|
||||
* display the profile of the user
|
||||
*/
|
||||
private void displayProfile() {
|
||||
socialService.getUserContext(getUserToShowId(), new AsyncCallback<UserContext>() {
|
||||
@Override
|
||||
public void onSuccess(UserContext result) {
|
||||
|
@ -44,21 +75,27 @@ public class SocialProfile implements EntryPoint {
|
|||
dispProfile.showError(caught.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
RootPanel.get("SocialProfileDiv").add(mainPanel);
|
||||
}
|
||||
|
||||
private void checkLinkedInAuthZ() {
|
||||
/**
|
||||
*
|
||||
* @return the token if everything goers ok, null otherwise
|
||||
*/
|
||||
private String checkLinkedInAuthZ() {
|
||||
if (Window.Location.getParameter("error") != null) {
|
||||
mainPanel.add(new ErrorAlert());
|
||||
} else {
|
||||
String code = Window.Location.getParameter("code");
|
||||
String controlSequence = Window.Location.getParameter("state");
|
||||
GWT.log("key="+code+" state="+controlSequence);
|
||||
GWT.log("state="+controlSequence);
|
||||
mainPanel.add(new OkAlert());
|
||||
mainPanel.add(new ErrorAlert("it seems you denied our request to import your professional summary from LinkedIn."));
|
||||
return null;
|
||||
}
|
||||
String code = Window.Location.getParameter("code");
|
||||
String controlSequence = Window.Location.getParameter("state");
|
||||
String cSeq2Compare = Cookies.getCookie(DisplayProfile.CONTROL_SEQUENCE_COOKIE);
|
||||
if (controlSequence.compareTo(cSeq2Compare) != 0) {
|
||||
mainPanel.add(new ErrorAlert("Something went wrong when importing your professional summary from LinkedIn, please try again."));
|
||||
return null;
|
||||
}
|
||||
|
||||
GWT.log("key="+code+" state="+controlSequence);
|
||||
GWT.log("state="+controlSequence);
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,7 +111,7 @@ public class SocialProfile implements EntryPoint {
|
|||
}
|
||||
/**
|
||||
*
|
||||
* @return true if either the user
|
||||
* @return true if the user has clicked import from LinkedIn
|
||||
*/
|
||||
private boolean isUserAuthZFromLinkedIn() {
|
||||
if (Window.Location.getParameter("error") != null || Window.Location.getParameter("code") != null)
|
||||
|
|
|
@ -15,4 +15,6 @@ public interface SocialService extends RemoteService {
|
|||
Boolean saveHeadline(String newHeadline);
|
||||
|
||||
Boolean saveIsti(String institution);
|
||||
|
||||
Boolean fetchUserProfile(String authCode, String redirectURI);
|
||||
}
|
||||
|
|
|
@ -12,4 +12,6 @@ public interface SocialServiceAsync {
|
|||
|
||||
void saveIsti(String institution, AsyncCallback<Boolean> callback);
|
||||
|
||||
void fetchUserProfile(String authCode, String redirectURI, AsyncCallback<Boolean> callback);
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.google.gwt.event.dom.client.ClickHandler;
|
|||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.Cookies;
|
||||
import com.google.gwt.user.client.Random;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.Window.Location;
|
||||
|
@ -44,8 +45,11 @@ public class DisplayProfile extends Composite {
|
|||
public static final String loading = GWT.getModuleBaseURL() + "../images/avatarLoader.gif";
|
||||
public static final String savingImage = GWT.getModuleBaseURL() + "../images/saving.gif";
|
||||
public static final String GET_OID_PARAMETER = "oid";
|
||||
public static final String CONTROL_SEQUENCE_COOKIE = "CSRF-check-d4science";
|
||||
|
||||
private final SocialServiceAsync socialService = GWT.create(SocialService.class);
|
||||
|
||||
|
||||
@UiField HTMLPanel mainPanel;
|
||||
@UiField Image avatarImage;
|
||||
@UiField HTML userFullName;
|
||||
|
@ -127,15 +131,20 @@ public class DisplayProfile extends Composite {
|
|||
|
||||
importButton.setVisible(true);
|
||||
importButton.addClickHandler(new ClickHandler() {
|
||||
//TODO: make it a runtime resource
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
String OAUTH2_SERVICE = "https://www.linkedin.com/uas/oauth2/authorization?response_type=code";
|
||||
String D4S_APP_ID = "77n7r4c9nwuwk2";
|
||||
String controlSequence = getRandomString();
|
||||
|
||||
//needed to prevent Cross Site Request Forgery attacks
|
||||
Cookies.setCookie(CONTROL_SEQUENCE_COOKIE, controlSequence);
|
||||
|
||||
String url = OAUTH2_SERVICE + ""
|
||||
+ "&client_id="+D4S_APP_ID
|
||||
+ "&state="+controlSequence
|
||||
+ "&redirect_uri="+Location.getHref();
|
||||
+ "&redirect_uri="+getRedirectURI();
|
||||
|
||||
Location.assign(url);
|
||||
}
|
||||
|
@ -152,6 +161,17 @@ public class DisplayProfile extends Composite {
|
|||
messageButton.setVisible(true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @return the redirect uri when authorized (or not) by LinkedIn via oAuth2
|
||||
*/
|
||||
public static String getRedirectURI() {
|
||||
String redirectURI = Window.Location.getProtocol()+"//"+Window.Location.getHost()+Window.Location.getPath();
|
||||
//development case
|
||||
if (Window.Location.getParameter("gwt.codesvr") != null)
|
||||
return redirectURI+"?gwt.codesvr=127.0.0.1:9997";
|
||||
return redirectURI;
|
||||
}
|
||||
|
||||
@UiHandler("editHeadline")
|
||||
void onEditHeadlineClick(ClickEvent e) {
|
||||
|
@ -311,8 +331,6 @@ public class DisplayProfile extends Composite {
|
|||
.replaceAll(">", ">");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String getRandomString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i=0;i<20;i++) {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package org.gcube.portlets.user.socialprofile.client.ui;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
|
@ -12,10 +14,11 @@ public class ErrorAlert extends Composite {
|
|||
|
||||
interface ErrorAlertUiBinder extends UiBinder<Widget, ErrorAlert> {
|
||||
}
|
||||
public ErrorAlert() {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
}
|
||||
public ErrorAlert(String firstName) {
|
||||
|
||||
@UiField Element errorMessage;
|
||||
|
||||
public ErrorAlert(String message) {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
errorMessage.setInnerText(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel styleName="{style.alert}">
|
||||
<span style="font-weight: bold;"> Import Error:</span> it seems you denied our request to import from LinkedIn.
|
||||
<span style="font-weight: bold;"> Import Error: </span><span ui:field="errorMessage"></span>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
|
@ -1,7 +1,9 @@
|
|||
package org.gcube.portlets.user.socialprofile.client.ui;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
|
@ -11,9 +13,10 @@ public class OkAlert extends Composite {
|
|||
|
||||
interface OkAlertUiBinder extends UiBinder<Widget, OkAlert> {
|
||||
}
|
||||
|
||||
public OkAlert() {
|
||||
@UiField Element message;
|
||||
public OkAlert(String message2Show) {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
message.setInnerText(message2Show);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel styleName="{style.alert}">
|
||||
Import operation completed successfully.
|
||||
<span ui:field="message"></span>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
|
@ -1,7 +1,23 @@
|
|||
package org.gcube.portlets.user.socialprofile.server;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.gcube.application.framework.core.session.ASLSession;
|
||||
import org.gcube.application.framework.core.session.SessionManager;
|
||||
import org.gcube.portal.custom.communitymanager.OrganizationsUtil;
|
||||
|
@ -9,12 +25,12 @@ import org.gcube.portal.custom.scopemanager.scopehelper.ScopeHelper;
|
|||
import org.gcube.portal.databook.shared.UserInfo;
|
||||
import org.gcube.portlets.user.socialprofile.client.SocialService;
|
||||
import org.gcube.portlets.user.socialprofile.shared.UserContext;
|
||||
import org.json.simple.parser.ContainerFactory;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
||||
import com.liferay.portal.kernel.exception.PortalException;
|
||||
import com.liferay.portal.kernel.exception.SystemException;
|
||||
import com.liferay.portal.kernel.util.WebKeys;
|
||||
import com.liferay.portal.model.User;
|
||||
import com.liferay.portal.service.UserLocalServiceUtil;
|
||||
|
@ -204,6 +220,98 @@ public class SocialServiceImpl extends RemoteServiceServlet implements SocialSer
|
|||
return html.replaceAll("&", "&").replaceAll("<", "<")
|
||||
.replaceAll(">", ">");
|
||||
}
|
||||
@Override
|
||||
public Boolean fetchUserProfile(String authCode, String redirectURI) {
|
||||
try {
|
||||
HttpClient httpClient = HttpClients.createDefault();
|
||||
HttpPost httpPost = new HttpPost("https://www.linkedin.com/uas/oauth2/accessToken");
|
||||
|
||||
// Request parameters and other properties.
|
||||
ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(5);
|
||||
params.add(new BasicNameValuePair("grant_type", "authorization_code"));
|
||||
params.add(new BasicNameValuePair("code", authCode));
|
||||
params.add(new BasicNameValuePair("redirect_uri", redirectURI));
|
||||
params.add(new BasicNameValuePair("client_id", "xxx"));
|
||||
params.add(new BasicNameValuePair("client_secret", "xxx"));
|
||||
|
||||
httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
//Execute and get the response.
|
||||
HttpResponse httpResponse = httpClient.execute(httpPost);
|
||||
HttpEntity entity = httpResponse.getEntity();
|
||||
|
||||
if (entity != null) {
|
||||
InputStream myInputStream = entity.getContent();
|
||||
try {
|
||||
String jsonText = IOUtils.toString(myInputStream, "UTF-8");
|
||||
_log.debug("LinkedIn response: " + jsonText);
|
||||
if (jsonText == null)
|
||||
return false;
|
||||
|
||||
JSONParser parser = new JSONParser();
|
||||
@SuppressWarnings("rawtypes")
|
||||
ContainerFactory containerFactory = new ContainerFactory(){
|
||||
public List creatArrayContainer() {
|
||||
return new LinkedList();
|
||||
}
|
||||
|
||||
public Map createObjectContainer() {
|
||||
return new LinkedHashMap();
|
||||
}
|
||||
|
||||
};
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> json = (Map<String, String>) parser.parse(jsonText, containerFactory);
|
||||
|
||||
if (json.get("error") != null)
|
||||
return false;
|
||||
|
||||
String token = json.get("access_token");
|
||||
if (token == null)
|
||||
return false;
|
||||
|
||||
return parseProfile(httpClient, token);
|
||||
}
|
||||
finally {
|
||||
myInputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean parseProfile(HttpClient httpClient, String token) {
|
||||
// HttpGet request = new HttpGet("https://api.linkedin.com/v1/people/~");
|
||||
|
||||
HttpGet request = new HttpGet("https://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,summary,location:(name),industry)");
|
||||
|
||||
// add request header
|
||||
request.addHeader("Authorization", "Bearer " + token);
|
||||
try {
|
||||
HttpResponse httpResponse = httpClient.execute(request);
|
||||
HttpEntity entity = httpResponse.getEntity();
|
||||
|
||||
if (entity != null) {
|
||||
InputStream myInputStream = entity.getContent();
|
||||
try {
|
||||
String xmlResponse = IOUtils.toString(myInputStream, "UTF-8");
|
||||
_log.debug("LinkedIn xmlResponse: " + xmlResponse);
|
||||
}
|
||||
finally {
|
||||
myInputStream.close();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
log4j.rootLogger=DEBUG, A1
|
||||
log4j.appender.A1=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
||||
|
||||
# Print the date in ISO 8601 format
|
||||
log4j.appender.A1.layout.ConversionPattern=%d %-5p %c - %m%n
|
||||
|
||||
# Print only messages of level TRACE or above in the package org.gcube
|
||||
log4j.logger.org.gcube=TRACE
|
||||
log4j.logger.org.gcube.application.framework.core.session=INFO
|
||||
log4j.logger.org.gcube.contentmanager=ERROR
|
||||
log4j.logger.org.gcube.common.scope=ERROR
|
||||
log4j.logger.org.gcube.contentmanagement=ERROR
|
||||
log4j.logger.org.gcube.resources.discovery.icclient=ERROR
|
||||
log4j.logger.org.gcube.common.clients=ERROR
|
||||
log4j.logger.org.gcube.common.homelibrary.jcr=ERROR
|
||||
log4j.logger.org.gcube.application.framework.accesslogger=ERROR
|
||||
log4j.logger.org.apache.pdfbox.util.PDFStreamEngine=ERROR
|
Loading…
Reference in New Issue