Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
titlegateway-sso-portlet.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="org.jasig.portlet.proxy.mvc.portlet.gateway" />
    <context:annotation-config />

    <bean
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:configuration.properties" />
    </bean>
    <util:list id="gatewayEntries" scope="session">
        <!--
 <bean class="org.jasig.portlet.proxy.mvc.portlet.gateway.GatewayEntry" p:name="MyZimbra"         Gateway SSO allows the user  p:iconUrl="/ResourceServingWebapp/rs/tango/0.8.90/32x32/apps/internet-mail.png">

      to sign onto remote systems through capture of credentials and
     <property name="authenticationFormModifier">      replay of those credentials on remote systems.  Each bean in <util:list>the contentRequest list is for a
            different system.  <!-- This bean modifies a special field that alters the location to POST the form data to -->The parameters property lists the fields that will be added to a form and then
            submitted to the proxiedLocation in order to authenticate.   <bean id="step1" 
						class="org.jasig.portlet.proxy.service.web.MyCustomClass"  
						scope="session" 
						p:fieldName="proxiedLocation"/>The formFieldImpl class contains three
            fields: the field name, value, and whether the field is secured.  <bean id="step2" 
						class="org.jasig.portlet.proxy.service.web.MyCustomClass2" 
						scope="singleton" 
						p:fieldName="testField" />Secured is only relevant at this
            point for the portlet preferences interceptor, since </util:list>those preferences must be stored in the database
     </property>       and are presented to the user in an HTML password input <property name="contentRequests">
     field instead of an HTML text input field.

         <util:map>   The following bean shows two interceptors. Refer to those two classes for the format of values that
 <entry>           will be substituted.

          <key>  userInfoUrlParameterizingPreInterceptor - will replace parameters with information from the portal's userInfo.

            userPreferencesPreInterceptor - will <bean class="org.jasig.portlet.proxy.service.web.HttpContentRequestImpl"
     replace parameters with information stored in portal preferences
            for the current user.

           p:proxiedLocation="https://zimbra.unicon.net/zimbra/"
                 This bean also demonstrates an optional whitelist of roles defined in portlet.xml.  If any roles are
            specified and the user  p:form="true" p:method="POST">
           is not in any of them, the gateway entry does not appear on the UI.

            This bean also demonstrates a custom java <property name="parameters">
         class ExampleCustomFormModifier that modifies the form by invoking another system to obtain
            a token that must be embedded in the POST URL with a special name. <util:map> It also adds the calculated field
            as a form field so custom javascript (custom-javascript.js) can be executed before the form is posted to perform additional
   <entry>         custom operations, in this case to also set the window name to the calculated field.
        -->
        <bean    <key><value>loginOp</value></key>class="org.jasig.portlet.proxy.mvc.portlet.gateway.GatewayEntry" p:name="MyZimbra"
                     p:iconUrl="/ResourceServingWebapp/rs/tango/0.8.90/32x32/apps/internet-mail.png"
              p:javascriptFile="/WebProxyPortlet/scripts/custom-javascript.js">

            <!-- Custom java form fields.  Beans in list must <beanimplement class="org.jasig.portlet.proxy.mvc.service.web.FormFieldImpl"IAuthenticationFormModifier
                interface. They can add form fields based on custom logic, or modifying the url to submit to. -->
                  p:<property name="loginOp" p:value="login"/authenticationFormModifier">
                <util:list>
                       </entry><bean class="org.jasig.portlet.proxy.service.web.ExampleCustomFormModifier"/>
                </util:list>
            </property>

         <entry>   <property name="contentRequests">
                <util:map>
                    <entry>
      <key><value>username</value></key>                  <key>
                            <bean class="org.jasig.portlet.proxy.service.web.FormFieldImpl"HttpContentRequestImpl"
                                  p:proxiedLocation="https://zimbra.unicon.net/zimbra/"
                                  p:nameform="usernametrue" p:valuemethod="{prefs.myzimbra.uid}"/POST">
                                <property name="parameters">
      </entry>                              <util:map>
                                        <entry>
                                            <key><value>password<<key><value>username</value></key>
                                            <bean class="org.jasig.portlet.proxy.service.web.FormFieldImpl"
                                                    p:name="passwordusername" p:value="{prefs.myzimbra.pwd}" p:secured="trueuid}"/>
                                        </entry>
                                    </util:map>      <entry>
                          </property>                             </bean>
<key><value>password</value></key>
                       </key>                     <bean class="org.jasig.portlet.proxy.service.web.FormFieldImpl"
  <util:list>                                <value>userInfoUrlParameterizingPreInterceptor</value>                p:name="password" p:value="{prefs.myzimbra.pwd}" p:secured="true"/>
          <value>UserPreferencesPreInterceptor</value>                         </util:list>     </entry>
               </entry>                 </util:map>        <entry>
    </property>         </bean>  		<!-- additional external systems to display --> 		<bean ...></bean>      </util:list>     <bean class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping">         <property name="interceptors"><bean class="org.jasig.portlet.proxy.mvc.MinimizedStateHandlerInterceptor"/></property> <key><value>loginOp</value></key>
     </bean>

</beans>

GatewayEntry

Each external systems to which you want to connect has its own GatewayEntry record.  This record contains the name and location of the Icon to represent the application.   It also contains a list of HttpContentRequestImpl records and any external logic to be executed.

HttpContentRequestImpl

...

                                       <bean class="org.jasig.portlet.proxy.service.web.FormFieldImpl"
                                                  p:name="loginOp" p:value="login"/>
                                        </entry>
                                        <entry>
                                            <key><value>client</value></key>
                                            <bean class="org.jasig.portlet.proxy.service.web.FormFieldImpl"
                                                  p:name="client" p:value="preferred"/>
                                        </entry>
                                    </util:map>
                                </property>
                            </bean>
                        </key>
                        <util:list>
                            <ref bean="userInfoUrlParameterizingPreInterceptor" />
                            <ref bean="UserPreferencesPreInterceptor" />
                        </util:list>
                    </entry>
                </util:map>
            </property>
            <!-- Whitelist of roles (from PAGS, SmartLDAP, internal roles, etc.) that this entry shows up for.  If no roleWhitelistProperty, then everyone has access to the entry. -->
            <property name="roleWhitelist">
                <list>
                    <value>Staff</value>
                </list>
            </property>
        </bean>


		<!-- additional external systems to display -->
		<bean ...></bean> 
    </util:list>
    <bean class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="interceptors"><bean class="org.jasig.portlet.proxy.mvc.MinimizedStateHandlerInterceptor"/></property>
    </bean>

</beans>

GatewayEntry

Each external systems to which you want to connect has its own GatewayEntry record.  This record contains the name and location of the Icon to represent the application.   It also contains a list of HttpContentRequestImpl records and any external logic to be executed.

HttpContentRequestImpl

In theory each GatewayEntry could have multiple HttpContentRequestImpl records associated with it; in practice, each GatewayEntry would only have one HttpContentRequestImpl record (see 

Jira Legacy
serverJASIG Issue Tracker
serverId76221f40-4501-3df1-8578-6c87908cbdf7
keyWPP-80
) .  This record contains the web address that will receive the form submission, the HTTP method type (GET, POST, PUT, DELETE), and a list of form fields to be included in the form submission.

...

Java Beans that implement IAuthenticationFormModifier can be embedded in your Gateway SSO to support more complicated scenarios.  The user can create their own Java Bean that implements the IAuthenticationFormModifier interface and include it in the portlet definition.  When the controller gathers all of the information required by the JSP to render, in addition to any fields defined in the associated FormFieldImpl fields, it will add a new field for each ExternalLogic bean.

For example, say you have an external system to which you wish to login.  Before you actually login, however, you need to retrieve a token from another system and include it in the submitted form or on the form's action field.  You can write a custom logic bean that will retrieve that value and include it as a field in the submission.  If you wish to create a custom form action, you could return a field named "proxiedLocation" , which would override the proxied location stored with the HttpContentRequestImpl field.

This is how you might add IAuthenticationFormModifier to your portlet definition file

...

titleIncluding ExternalLogic in your portlet

Gateway SSO to support more complicated scenarios.  The user can create their own Java Bean that implements the IAuthenticationFormModifier interface and include it in the portlet definition.  The IAuthenticationFormModifier classes can add or remove fields from the form or change the url the form posts to. 

For example, say you have an external system to which you wish to login.  Before you actually login, however, you need to retrieve a token from another system and include it in the submitted form or on the form's action field.  You can write a custom logic bean that will retrieve that value and include it as a field in the submission.

This is how you might add IAuthenticationFormModifier to your portlet definition file

Code Block
titleIncluding ExternalLogic in your portlet
          <bean class="org.jasig.portlet.proxy.mvc.portlet.gateway.GatewayEntry" p:name="MyZimbra"
              p:iconUrl="/ResourceServingWebapp/rs/tango/0.8.90/32x32/apps/internet-mail.png">

            <property name="authenticationFormModifier">
                <util:list>
                    <bean class="org.jasig.portlet.proxy.mvcservice.portlet.gateway.GatewayEntry" p:name="MyZimbra"web.ExampleCustomFormModifier"/>
                </util:list>
            </property>

			...
   p:iconUrl="/ResourceServingWebapp/rs/tango/0.8.90/32x32/apps/internet-mail.png">

            <property name="authenticationFormModifier">
                <util:list>
                    <bean id="step1" 
						class="org.jasig.portlet.proxy.service.web.MyCustomClass"  
						scope="session" 
						p:fieldName="proxiedLocation"/>
                    <bean id="step2" 
								</bean> 

 

IAuthenticationFormModifier

IAuthenticationFormModifier is an interface that must be implemented by any classes that wish to hook into the IAuthenticationFormModifier process.  It has the method:

  • void modifyHttpContentRequest(HttpContentRequestImpl contentRequest, PortletPreferences preferences)

Your implementation can be as simple or as complicated as needed and can add form fields, change the Url to submit to, etc.  PortletPreferences are available to your bean.

Custom JavaScript code

The gateway page can be configured to obtain and execute a custom javascript file to perform whatever behaviors are necessary for the single sign-on.  For example, the window name can be changed to match some particular value.  The javascript has full access to the form that will be submitted and can perform whatever custom logic is desired.  The javascript is loaded and executed using an eval() javascript statement, so troubleshooting is a bit more difficult as you cannot set breakpoints in the javascript. To add custom javascript to the execution, specify its location in the GatewayEntry bean; e.g.

Code Block
languagehtml/xml
titleSpecifying custom javascript for sign-on\
<bean class="org.jasig.portlet.proxy.servicemvc.web.MyCustomClass2" 
						scope="singleton" 
						p:fieldName="testField" />
                </util:list>
portlet.gateway.GatewayEntry" p:name="WebAdvisor"
           </property>
			...
		</bean> 

 

IAuthenticationFormModifier

IAuthenticationFormModifier is an interface that must be implemented by any classes that wish to hook into the IAuthenticationFormModifier process.  The methods are:

  • getFieldName() - returns the field name to be included in the list of parameters
  • getResult(PortletPreferences preferences) - returns the value of the field.

...

p:iconUrl="/ResourceServingWebapp/rs/tango/0.8.90/32x32/apps/internet-web-browser.png"
      p:javascriptFile="/WebProxyPortlet/scripts/custom-javascript.js">
...
</bean>

Security Considerations

  • uPortal should use HTTPS for its connections to the browser to insure user passwords are not intercepted in transit to the user's browser
  • If using UserPreferencePreInterceptor, the encryption key must be changed from the default (an error message is displayed in the log files if the key is the default value)
  • The target URLs to submit to (proxiedLocation) should be HTTPS (required by default)
  • The HTTP response including sensitive user information is set to request not caching the response.  However the user's passwords are not encrypted in transit other than the encryption used by HTTPS.  If greater security is required, you can encrypt the password for the gateway form response and add a javascript library to decrypt it, though this does not add much security since sophisticated users can figure this out.