completed implementation for Feature #5143: smartgears service authentication portlet with client id and secret checking

git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/user/my-vres@141567 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Massimiliano Assante 2017-01-13 16:23:37 +00:00
parent dd69469e4e
commit 5fec8824b6
9 changed files with 174 additions and 31 deletions

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/my-vres-2.2.0-SNAPSHOT/WEB-INF/classes" path="src/main/java">
<classpathentry kind="src" output="target/my-vres-2.3.0-SNAPSHOT/WEB-INF/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/my-vres-2.2.0-SNAPSHOT/WEB-INF/classes" path="src/main/resources">
<classpathentry excluding="**" kind="src" output="target/my-vres-2.3.0-SNAPSHOT/WEB-INF/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
@ -38,5 +38,5 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/my-vres-2.2.0-SNAPSHOT/WEB-INF/classes"/>
<classpathentry kind="output" path="target/my-vres-2.3.0-SNAPSHOT/WEB-INF/classes"/>
</classpath>

View File

@ -1,18 +1,30 @@
<ReleaseNotes>
<Changeset component="org.gcube.portlet.user.my-vres.2-2-0" date="2016-11-17">
<Changeset component="org.gcube.portlet.user.my-vres.2-3-0"
date="2017-01-07">
<Change>Fix for bug not allowing to click on vre missing logos</Change>
<Change>Adapted so support VRE selection upon authorisation requests</Change>
</Changeset>
<Changeset component="org.gcube.portlet.user.my-vres.2-2-0"
date="2016-11-17">
<Change>Removed ASL Session</Change>
<Change>Implemented Feature #4877 remove VRE association to single Category constraint</Change>
<Change>Implemented Feature #4877 remove VRE association to single
Category constraint</Change>
</Changeset>
<Changeset component="org.gcube.portlet.user.my-vres.2-1-0" date="2016-09-12">
<Change>Shows only the virtual groups available in the Site it is deployed on</Change>
<Change>VRE was not updated in the portlet due to liferay versioning of Document Library</Change>
<Changeset component="org.gcube.portlet.user.my-vres.2-1-0"
date="2016-09-12">
<Change>Shows only the virtual groups available in the Site it is
deployed on</Change>
<Change>VRE was not updated in the portlet due to liferay versioning
of Document Library</Change>
</Changeset>
<Changeset component="org.gcube.portlet.user.my-vres.2-0-1" date="2016-04-02">
<Changeset component="org.gcube.portlet.user.my-vres.2-0-1"
date="2016-04-02">
<Change>Ported to Liferay 6.2</Change>
</Changeset>
<Changeset component="org.gcube.portlet.user.my-vres.1-6-0"
date="2015-11-22">
<Change>Bug #1855, does not show join welcome message to new users anymore</Change>
<Change>Bug #1855, does not show join welcome message to new users
anymore</Change>
<Change>Feature #861, categorized VREs by virtualGroups</Change>
</Changeset>
<Changeset component="org.gcube.portlet.user.my-vres.1-5-0"

17
pom.xml
View File

@ -13,7 +13,7 @@
<groupId>org.gcube.portlets.user</groupId>
<artifactId>my-vres</artifactId>
<packaging>war</packaging>
<version>2.2.0-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<name>My VREs Portlet</name>
<description>
gCube My VREs Portlet shows only the VO and VREs a user is member of, divided by category.
@ -65,6 +65,21 @@
<groupId>org.gcube.dvos</groupId>
<artifactId>usermanagement-core</artifactId>
</dependency>
<!-- FWS DEPS -->
<dependency>
<groupId>org.gcube.resources.discovery</groupId>
<artifactId>ic-client</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope-maps</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-encryption</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>portal-service</artifactId>

View File

@ -4,11 +4,18 @@ public class GetParameters {
String redirectURI;
String state;
String context;
public GetParameters(String redirectURI, String state, String context) {
String clientId;
String clientSecret;
public GetParameters(String redirectURI, String state, String context, String clientId, String clientSecret) {
super();
this.redirectURI = redirectURI;
this.state = state;
this.context = context;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
public String getRedirectURI() {
@ -23,10 +30,20 @@ public class GetParameters {
return context;
}
public String getClientId() {
return clientId;
}
public String getClientSecret() {
return clientSecret;
}
@Override
public String toString() {
return "GetParameters [redirectURI=" + redirectURI + ", state=" + state + ", context=" + context + "]";
return "GetParameters [redirectURI=" + redirectURI + ", state=" + state + ", context=" + context + ", clientId="
+ clientId + ", clientSecret=" + clientSecret + "]";
}
}

View File

@ -19,6 +19,8 @@ public class MyVREs implements EntryPoint {
public static final String GET_REDIRECTURI_PARAMETER = "redirect_uri";
public static final String GET_STATE_PARAMETER = "state";
public static final String GET_CONTEXT_PARAMETER = "context";
public static final String GET_CLIENT_ID_PARAMETER = "client_id";
public static final String GET_CLIENT_SECRET_PARAMETER = "client_secret";
public static final String GET_AUTH_TOKEN_PARAMETER = "gcube-token";
@ -47,20 +49,23 @@ public class MyVREs implements EntryPoint {
RootPanel.get("myVREsDIV").add(new VresPanel(params));
}
else {
myVREsService.getUserToken(params.context, params.state, new AsyncCallback<AuthorizationBean>() {
myVREsService.getUserToken(params.context, params.state, params.clientId, params.clientSecret, new AsyncCallback<AuthorizationBean>() {
@Override
public void onSuccess(AuthorizationBean result) {
if (result.isSuccess()) {
Location.assign(params.redirectURI+"?"+GET_AUTH_TOKEN_PARAMETER+"="+result.getToken()+"&"+GET_STATE_PARAMETER+"="+result.getState());
} else {
RootPanel.get("myVREsDIV").add(new HTML("There were issues in managing this request: " + result.getErrorDescription()));
HTML message = new HTML("There were issues in managing this request: " + result.getErrorDescription());
message.setStyleName("portlet-msg-error");
RootPanel.get("myVREsDIV").insert(message, 0);
}
}
@Override
public void onFailure(Throwable caught) {
RootPanel.get("myVREsDIV").add(new HTML("An error occurred in the server: " + caught.getMessage()));
HTML message = new HTML("An error occurred in the server: " + caught.getMessage());
message.setStyleName("portlet-msg-error");
RootPanel.get("myVREsDIV").insert(message, 0);
}
});
}
@ -74,6 +79,9 @@ public class MyVREs implements EntryPoint {
String redirectURI = Window.Location.getParameter(GET_REDIRECTURI_PARAMETER);
String state = Window.Location.getParameter(GET_STATE_PARAMETER);
String context = Window.Location.getParameter(GET_CONTEXT_PARAMETER);
return new GetParameters(redirectURI, state, context);
String clientId = Window.Location.getParameter(GET_CLIENT_ID_PARAMETER);
String clientSecret = Window.Location.getParameter(GET_CLIENT_SECRET_PARAMETER);
return new GetParameters(redirectURI, state, context, clientId, clientSecret);
}
}

View File

@ -18,5 +18,5 @@ public interface MyVREsService extends RemoteService {
String getSiteLandingPagePath();
AuthorizationBean getUserToken(String context, String state);
AuthorizationBean getUserToken(String context, String state, String clientId, String clientSecret);
}

View File

@ -15,6 +15,7 @@ public interface MyVREsServiceAsync {
void getSiteLandingPagePath(AsyncCallback<String> callback);
void getUserToken(String context, String state, AsyncCallback<AuthorizationBean> callback);
void getUserToken(String context, String state, String clientId, String clientSecret,
AsyncCallback<AuthorizationBean> callback);
}

View File

@ -11,6 +11,7 @@ import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.rpc.AsyncCallback;
@ -34,7 +35,7 @@ public class ClickableVRE extends HTML {
public static final String LOADING_IMAGE = GWT.getModuleBaseURL() + "../images/loading.gif";
public static final String VLAB_IMAGE = GWT.getModuleBaseURL() + "../images/vlab.png";
private String html = "";
private HandlerRegistration handleReg;
public ClickableVRE(final MyVREsServiceAsync myVREsService, final VRE vre, final boolean showImage, final GetParameters params) {
super.setPixelSize(WIDTH, HEIGHT);
@ -61,13 +62,15 @@ public class ClickableVRE extends HTML {
if (params != null) {
addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
myVREsService.getUserToken(vre.getContext(), params.getState(), new AsyncCallback<AuthorizationBean>() {
myVREsService.getUserToken(vre.getContext(), params.getState(), params.getClientId(), params.getClientSecret(), new AsyncCallback<AuthorizationBean>() {
@Override
public void onSuccess(AuthorizationBean result) {
if (result.isSuccess()) {
Location.assign(params.getRedirectURI()+"?"+MyVREs.GET_AUTH_TOKEN_PARAMETER+"="+result.getToken()+"&"+MyVREs.GET_STATE_PARAMETER+"="+result.getState());
} else {
RootPanel.get("myVREsDIV").add(new HTML("There were issues in managing this request: " + result.getErrorDescription()));
HTML message = new HTML("There were issues in managing this request: " + result.getErrorDescription());
message.setStyleName("portlet-msg-error");
RootPanel.get("myVREsDIV").insert(message, 0);
}
}
@ -99,7 +102,7 @@ public class ClickableVRE extends HTML {
});
}
addMouseOverHandler(new MouseOverHandler() {
handleReg = addMouseOverHandler(new MouseOverHandler() {
@Override
public void onMouseOver(MouseOverEvent event) {
if (!showImage) {
@ -112,10 +115,14 @@ public class ClickableVRE extends HTML {
"<span style=\"vertical-align:middle; display: table-cell;\"><img style=\"width: " + imageWidth + "px;\" src=\"" +imageUrl + "\" /></span>" +
"</div>";
setHTML(html);
GWT.log("Show");
handleReg.removeHandler();
}
}
});
}
}

View File

@ -1,5 +1,8 @@
package org.gcube.portlet.user.my_vres.server;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@ -7,12 +10,19 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.gcube.common.encryption.StringEncrypter;
import org.gcube.common.portal.GCubePortalConstants;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
import org.gcube.common.resources.gcore.utils.Group;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.portlet.user.my_vres.client.MyVREsService;
import org.gcube.portlet.user.my_vres.shared.AuthorizationBean;
import org.gcube.portlet.user.my_vres.shared.UserBelonging;
import org.gcube.portlet.user.my_vres.shared.VRE;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.vomanagement.usermanagement.GroupManager;
import org.gcube.vomanagement.usermanagement.exception.GroupRetrievalFault;
import org.gcube.vomanagement.usermanagement.exception.UserManagementSystemException;
@ -44,7 +54,7 @@ public class MyVREsServiceImpl extends RemoteServiceServlet implements MyVREsSer
public static final String ADD_MORE_CATEGORY = "Add More";
public static final String ADD_MORE_IMAGE_PATH= "images/More.png";
private static final String SERVICE_ENDPOINT_CATEGORY = "Portal";
@Override
public String getSiteLandingPagePath() {
@ -247,7 +257,20 @@ public class MyVREsServiceImpl extends RemoteServiceServlet implements MyVREsSer
}
@Override
public AuthorizationBean getUserToken( String context, String state) {
public AuthorizationBean getUserToken(String context, String state, String clientId, String clientSecret) {
if (clientId == null || clientId.compareTo("")== 0) {
return new AuthorizationBean(null, null, false, "client_id is null, you MUST register your application to allow users connect with their D4Science Credentials");
}
if (clientSecret == null || clientSecret.compareTo("")== 0) {
return new AuthorizationBean(null, null, false, "client_secret is null, you MUST pass the clientSecret related to your client_id registered application to allow users connect with their D4Science Credentials");
}
String registeredClientSecret = getClientSecretFromIs(clientId);
if (registeredClientSecret == null) {
return new AuthorizationBean(null, null, false, "Your client_id ("+ clientId +") is not registered in the infrastructure, you MUST register your client_id to allow users connect with their D4Science Credentials");
}
if (registeredClientSecret.compareTo(clientSecret)!=0) {
return new AuthorizationBean(null, null, false, "The client_secret for clientId ("+ clientId +"), does not match");
}
if (state == null || state.compareTo("")== 0) {
return new AuthorizationBean(null, null, false, "State is null, please use a unique string value of your choice that is hard to guess (e.g. state=7d12bf13-111c-4f46-ab06-9e9e08ad377b). Used to prevent CSRF attacks");
}
@ -288,5 +311,65 @@ public class MyVREsServiceImpl extends RemoteServiceServlet implements MyVREsSer
return new AuthorizationBean(token, state, true, null);
}
//TODO: check the query, it doesn work
private List<ServiceEndpoint> getPortalConfigurationFromIS(String infrastructureName, String gatewayName) throws Exception {
String scope = "/" + infrastructureName;
String currScope = ScopeProvider.instance.get();
ScopeProvider.instance.set(scope);
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Category/text() eq '"+ SERVICE_ENDPOINT_CATEGORY +"'");
query.addCondition("$resource/Profile/Name/text() eq '"+ gatewayName +"'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> toReturn = client.submit(query);
ScopeProvider.instance.set(currScope);
return toReturn;
}
/**
* look for the clientId AccessEndpoint passes as parameter
* @param gatewayName
* @param clientId
* @return the client secret related to the id, or null if non existent
*/
private String getClientSecretFromIs(String clientId) {
PortalContext pContext = PortalContext.getConfiguration();
String gatewayName = pContext.getGatewayName(getThreadLocalRequest());
String scope = "/"+pContext.getInfrastructureName();
try {
List<ServiceEndpoint> list = getPortalConfigurationFromIS(pContext.getInfrastructureName(), gatewayName);
if (list.size() > 1) {
_log.error("Too many Service Endpoints having name " + gatewayName +" in this scope having Category " + SERVICE_ENDPOINT_CATEGORY);
}
else if (list.size() == 0){
_log.warn("There is no Service Endpoint having name " + gatewayName +" and Category " + SERVICE_ENDPOINT_CATEGORY + " in this scope: " + scope);
}
else {
for (ServiceEndpoint res : list) {
Group<AccessPoint> apGroup = res.profile().accessPoints();
AccessPoint[] accessPoints = (AccessPoint[]) apGroup.toArray(new AccessPoint[apGroup.size()]);
for (int i = 0; i < accessPoints.length; i++) {
if (accessPoints[i].name().compareTo(clientId) == 0) {
_log.info("Found credentials for " + clientId);
AccessPoint found = accessPoints[i];
//String thumbnailURL = found.address();
String encrPassword = found.password();
String clientSecret = "";
try {
clientSecret = StringEncrypter.getEncrypter().decrypt( encrPassword);
_log.debug("clientSecret for " + clientId + " found");
return clientSecret;
} catch (Exception e) {
_log.error("Something went wrong while decrypting password for " + clientId);
e.printStackTrace();
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return null;
}
}