Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WiP] Add the Soffit prototype to your dev environment; DO NOT MERGE! #665

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
<commons-dbcp.version>1.4</commons-dbcp.version>
<commons-fileupload.version>1.3.1</commons-fileupload.version>
<commons-httpclient.version>3.1</commons-httpclient.version>
<commons-httpcomponents.version>4.3.2</commons-httpcomponents.version>
<commons-httpcomponents.version>4.4.4</commons-httpcomponents.version>
<commons-io.version>2.4</commons-io.version>
<commons-lang.version>2.6</commons-lang.version>
<commons-lang3.version>3.3.2</commons-lang3.version>
Expand Down Expand Up @@ -215,6 +215,7 @@
<resource-server.version>1.0.43</resource-server.version>
<servlet-api.version>3.0.1</servlet-api.version>
<slf4j.version>1.7.7</slf4j.version>
<soffit.version>0.9.0-SNAPSHOT</soffit.version>
<spring-framework.version>3.2.9.RELEASE</spring-framework.version>
<spring-ldap.version>1.3.1.RELEASE</spring-ldap.version>
<spring-security.version>3.1.3.RELEASE</spring-security.version>
Expand Down Expand Up @@ -595,6 +596,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apereo.portal</groupId>
<artifactId>soffit</artifactId>
<version>${soffit.version}</version>
</dependency>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-runtime</artifactId>
Expand Down
13 changes: 12 additions & 1 deletion uportal-war/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

<name>uPortal WAR</name>
<description>The uPortal web application.</description>

<dependencies>
<!-- ***** Portal JDBC Driver ***** -->
<dependency>
Expand Down Expand Up @@ -234,6 +234,17 @@
<artifactId>oauth</artifactId>
</dependency>

<dependency>
<groupId>org.apereo.portal</groupId>
<artifactId>soffit</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-runtime</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.jasig.portal.soffit;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.apereo.portal.soffit.Headers;
import org.apereo.portal.soffit.connector.AbstractHeaderProvider;
import org.apereo.portal.soffit.model.v1_0.Bearer;
import org.apereo.portal.soffit.service.BearerService;
import org.jasig.portal.groups.IEntityGroup;
import org.jasig.portal.groups.IGroupMember;
import org.jasig.portal.security.IPerson;
import org.jasig.portal.services.GroupService;
import org.jasig.services.persondir.IPersonAttributeDao;
import org.jasig.services.persondir.IPersonAttributes;
import org.springframework.beans.factory.annotation.Autowired;

/**
* Prepares the standard HTTP Authorization header. This component is defined
* explicitly in the portlet context (not by annotation).
*
* @since 5.0
* @author drewwills
*/
public class AuthorizationHeaderProvider extends AbstractHeaderProvider {

@Autowired
private IPersonAttributeDao personAttributeDao;

@Autowired
private BearerService bearerService;

@Override
public Header createHeader(RenderRequest renderRequest, RenderResponse renderResponse) {

// Username
final String username = getUsername(renderRequest);

// Attributes
final Map<String,List<String>> attributes = new HashMap<>();
final IPersonAttributes person = personAttributeDao.getPerson(username);
if (person != null) {
for (Entry<String, List<Object>> y : person.getAttributes().entrySet()) {
final List<String> values = new ArrayList<>();
for (Object value : y.getValue()) {
if (value instanceof String) {
values.add((String) value);
}
}
attributes.put(y.getKey(), values);
}
}
logger.debug("Found the following user attributes for username='{}': {}", username, attributes);

// Groups
final List<String> groups = new ArrayList<>();
final IGroupMember groupMember = GroupService.getGroupMember(username, IPerson.class);
if (groupMember != null) {
Set<IEntityGroup> ancestors = groupMember.getAncestorGroups();
for (IEntityGroup g : ancestors) {
groups.add(g.getName());
}
}
logger.debug("Found the following group affiliations for username='{}': {}", username, groups);

// Expiration of the Bearer token
final PortletSession portletSession = renderRequest.getPortletSession();
final Date expires = new Date(
portletSession.getLastAccessedTime() + ((long) portletSession.getMaxInactiveInterval() * 1000L)
);

// Authorization header
final Bearer bearer = bearerService.createBearer(username, attributes, groups, expires);
final Header rslt = new BasicHeader(
Headers.AUTHORIZATION.getName(),
Headers.BEARER_TOKEN_PREFIX + bearer.getEncryptedToken());
logger.debug("Produced the following Authorization header for username='{}': {}", username, rslt);

return rslt;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/**
* Licensed to Apereo under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Apereo licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.jasig.portal.soffit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.apereo.portal.soffit.Headers;
import org.apereo.portal.soffit.connector.AbstractHeaderProvider;
import org.apereo.portal.soffit.model.v1_0.Definition;
import org.apereo.portal.soffit.service.DefinitionService;
import org.jasig.portal.i18n.ILocaleStore;
import org.jasig.portal.i18n.LocaleManager;
import org.jasig.portal.portlet.marketplace.IMarketplaceService;
import org.jasig.portal.portlet.marketplace.MarketplacePortletDefinition;
import org.jasig.portal.portlet.om.IPortletDefinition;
import org.jasig.portal.portlet.om.IPortletDefinitionParameter;
import org.jasig.portal.portlet.om.IPortletWindow;
import org.jasig.portal.portlet.om.IPortletWindowId;
import org.jasig.portal.portlet.om.PortletCategory;
import org.jasig.portal.portlet.registry.IPortletWindowRegistry;
import org.jasig.portal.security.IPerson;
import org.jasig.portal.security.IPersonManager;
import org.jasig.portal.url.IPortalRequestUtils;
import org.springframework.beans.factory.annotation.Autowired;

/**
* Prepares the custom HTTP X-Soffit-Definition header. This component is
* defined explicitly in the portlet context (not by annotation).
*
* @since 5.0
* @author drewwills
*/
public class DefinitionHeaderProvider extends AbstractHeaderProvider {

@Autowired
private IPortalRequestUtils portalRequestUtils;

@Autowired
private IPortletWindowRegistry portletWindowRegistry;

@Autowired
private IMarketplaceService marketplaceService;

@Autowired
private IPersonManager personManager;

@Autowired
private ILocaleStore localeStore;

@Autowired
private DefinitionService definitionService;

@Override
public Header createHeader(RenderRequest renderRequest, RenderResponse renderResponse) {

// Username
final String username = getUsername(renderRequest);

// Obtain the MarketplacePortletDefinition for this soffit
final HttpServletRequest httpr = portalRequestUtils.getCurrentPortalRequest();
final IPortletWindowId portletWindowId = portletWindowRegistry.getPortletWindowId(httpr, renderRequest.getWindowID());
final IPortletWindow portletWindow = portletWindowRegistry.getPortletWindow(httpr, portletWindowId);
final IPortletDefinition pdef = portletWindow.getPortletEntity().getPortletDefinition();
final MarketplacePortletDefinition mpdef = this.marketplaceService.getOrCreateMarketplacePortletDefinition(pdef);

final IPerson user = personManager.getPerson(httpr);
final Locale locale = getUserLocale(user);

// Title
final String title = mpdef.getTitle(locale.toString());

// FName
final String fname = mpdef.getFName();

// Description
final String description = mpdef.getDescription(locale.toString());

// Categories
List<String> categories = new ArrayList<>();
for (PortletCategory pc : mpdef.getCategories()) {
categories.add(pc.getName());
}

// Parameters
Map<String,List<String>> parameters = new HashMap<>();
for (IPortletDefinitionParameter param : mpdef.getParameters()) {
parameters.put(param.getName(), Collections.singletonList(param.getValue()));
}

final Definition definition = definitionService.createDefinition(title, fname,
description, categories, parameters, username, getExpiration(renderRequest));
final Header rslt = new BasicHeader(
Headers.DEFINITION.getName(),
definition.getEncryptedToken());
logger.debug("Produced the following {} header for username='{}': {}", Headers.DEFINITION.getName(), username, rslt);

return rslt;
}

/*
* Implementation
*/

private Locale getUserLocale(IPerson user) {
// get user locale
Locale[] locales = localeStore.getUserLocales(user);
LocaleManager localeManager = new LocaleManager(user, locales);
Locale rslt = localeManager.getLocales()[0];
return rslt;
}

}
10 changes: 10 additions & 0 deletions uportal-war/src/main/resources/properties/ehcache.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1997,4 +1997,14 @@
eternal="false" maxElementsInMemory="2000" overflowToDisk="false" diskPersistent="false"
timeToIdleSeconds="0" timeToLiveSeconds="300" memoryStoreEvictionPolicy="LRU" statistics="true" />

<!--
| Caches out output of remote soffits; timeToLiveSeconds will be set on
| each Element according to the cache-control header send by the remote soffit.
| - 1 x unique combination of (soffit+mode+windowState) [x user for private scope]
| - not replicated
+-->
<cache name="org.apereo.portlet.soffit.connector.SoffitConnectorController.RESPONSE_CACHE"
eternal="false" maxElementsInMemory="2000" overflowToDisk="false" diskPersistent="false"
timeToIdleSeconds="0" timeToLiveSeconds="0" memoryStoreEvictionPolicy="LRU" statistics="true" />

</ehcache>
14 changes: 14 additions & 0 deletions uportal-war/src/main/resources/properties/portal.properties
Original file line number Diff line number Diff line change
Expand Up @@ -768,4 +768,18 @@ org.jasig.portal.tincan-api.enabled=false
# org.jasig.rest.interceptor.basic-auth.scorm-cloud-lrs.username=UsernameForProvider
# org.jasig.rest.interceptor.basic-auth.scorm-cloud-lrs.password=PasswordForProvider

# Signature Key (Soffit)
# ----------------------
# Uncomment and change the value of this setting. 'CHANGEME' is the default
# value; it may work (if both sides of the transaction have the default), but
# isn't secure and will produce a WARNING.
#
#org.apereo.portal.soffit.jwt.signatureKey=CHANGEME

# Encryption Password (Soffit)
# ----------------------------
# Uncomment and change the value of this setting. 'CHANGEME' is the default
# value; it may work (if both sides of the transaction have the default), but
# isn't secure and will produce a WARNING.
#
#org.apereo.portal.soffit.jwt.encryptionPassword=CHANGEME
29 changes: 28 additions & 1 deletion uportal-war/src/main/webapp/WEB-INF/portlet.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1105,10 +1105,37 @@
</container-runtime-option>
</portlet>

<portlet>
<portlet-name>Soffit Connector</portlet-name>
<display-name xml:lang="en">Soffit Connector</display-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>classpath:/org/apereo/portal/soffit/connector/connector-portlet.xml</value>
</init-param>
<expiration-cache>0</expiration-cache><!-- Never cache; we'll cache internally -->
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>EDIT</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<portlet-info>
<title>Soffit Connector</title>
</portlet-info>
<portlet-preferences>
<preference>
<!-- This preference identifies the remote service -->
<name>org.apereo.portlet.soffit.connector.SoffitConnectorController.serviceUrl</name>
</preference>
</portlet-preferences>
</portlet>

<custom-portlet-mode>
<description>Allows the portlet to render a preferences edit UI during publishing</description>
<portlet-mode>config</portlet-mode>
</custom-portlet-mode>
</custom-portlet-mode>

<user-attribute>
<description>The P3P username attribute</description>
Expand Down