Prashant Dighe's Weblog

Saturday Jun 21, 2008

Leopard problems and some solutions

The editor applications (like TextEdit and others) do not take the cursor along when you page up/dn. So you scroll down 5 pages and try to place the cursor using the arrow keys and it suddenly jumps back to 5 pages up. You must click mouse after scrolling down. Perhaps my expectations about usability were too high.

NFS auto mounts on /net. This is neat.

Configuration for auto mounting of home dir was very easy as compared to Tiger.
1. Set uid same as NIS uid
    System Preferences > Accounts > Right click user > "Advanced Options"
2. Set password same as NIS password
3. Edit /etc/auto_home 
    Comment out +auto_home
    Add line like this: *    home-dir-host:/dir1/dir2/&

I also prefer to set the same user name and group id as NIS which makes it so easy for permissions and ssh w/o user name. But changing the group id was quite challenging till I found the right set of commands. The group id 10 is owner while I wanted it to be staff which was 20. To swap owner and staff group ids, execute the following commands:
dscl . list groups gid (notice staff is 20 and owner is 10)
sudo dscl . change groups/staff PrimaryGroupID 20 2020
sudo dscl . change groups/owner PrimaryGroupID 10 20
sudo dscl . change groups/staff PrimaryGroupID 2020 10
dscl . list groups gid (notice staff and owner are now reversed)

Terminal has tabs but can not set the tab title. Could not believe this, but its true. People are suggesting all kinds of hacks but none of them suit me. One can cycle tabs using cmd+shift+braces (braces or arrows). But if tab title can not be set, there is no way to find out which tab to select unless you go to the tab and see the window title. Too Bad! Liked the window groups though.

OpenOffice worked initially (for a few times) but then started hanging. Found out that its a known pain point and is mainly due to broken X11.
http://lists.apple.com/archives/x11-users/2007/Oct/msg00165.html
http://www.oooforum.org/forum/viewtopic.phtml?t=65161
http://shaunmcdonald131.blogspot.com/2008/03/ooo-possible-fix-for-command-timed-out.html
http://www.mail-archive.com/users@openoffice.org/msg82997.html

Not just OO, but even X11 stopped opening after a while. Could not even open xterm. Just hangs. Then found out that this was again a known issue.
http://forums.macosxhints.com/showthread.php?t=80171
http://homepage.mac.com/sao1/X11/
http://aaroniba.net/articles/x11-leopard.html
http://xquartz.macosforge.org/trac/wiki/X112.2.1

Installed XQuartz X11 to replace original X11. The problem is, this needs to be re-installed every time there is a software update. What a mess!

Installing new X11 did not fix OO. So finally blew away the original OO and installed OpenOffice.org 3 Aqua Beta which was released on May 1st, 2008.
http://porting.openoffice.org/mac/download/aqua.html
http://porting.openoffice.org/mac/download/aqua-Intel.html
Haven't tried exhaustively yet but hey, it at least works!  (looks really good)

You have to use X11 forwarding to execute X11 apps on remote machine.
The following use case does not work with X11 forwarding:
1. ssh as yourself to Solaris
2, su to root
3. launch X11 application. This fails with message:
    X11 connection rejected because of wrong authentication.  
    X connection to localhost:10.0 broken (explicit kill or server shutdown).

Need to run X11 apps like product installers on Solaris as root. So this was something essential for me. Had to workaround/hack as below, opening a security hole:
1. Login to Solaris server as root
2. Edit /etc/ssh/sshd_config
    PermitRootLogin yes
3. Restart sshd daemon
    grep and kill all sshd proceses and the daemon will restart again

Now you can ssh as root from Mac and run the X11 app.
    ssh -Y -l root solaris.example.com
May be there is a better and secure way that I do not know.

Sometimes during administration it just complains "No Such User" when you are logged in, but does not allow you to do anything unless relogin or reboot.

Wednesday May 07, 2008

Inter-Widget communication in cross-platform widgets


JavaONEProject WebSynergy is Sun's next generation web aggregation and presentation platform wherein,widgets developed using various programming languages and web technologies, like Java, Ruby and PHP, can co-exist and inter-communicate. For a demo, please visit our booth at JavaONE 2008, today or anytime this week. Alternatively, you may pick up a CD or a USB Memory Stick from the booth and try it out. The downloadable zip and instructions are also available.


RubySo how is inter-widget communication achieved? Well, "Whats the big deal?", someone may ask. Propreitory inter-widget communication can be acheived in many different ways. But these widgets use a standard defined by Java Portlet Specification 2.0 (JSR 286) known as public render parameters. And this makes all the difference.

PHPBut does this mean Ruby and PHP programmers have to first learn Java specification to be able to develop widgets? The answer is, absolutely not. That is why this becomes so important. Project WebSynergy uses Liferay's JRuby and PHP bridges to run the Ruby and PHP widgets. NetBeans 6.1 and Glassfish v3 already support Ruby/PHP. The native PHP support is in early access in NetBeans 6.1 but you can always write PHP code inside NetBeans. Project WebSynergy provides Portal Pack, which are NetBeans plugins for developing widgets. So the tools make all the difference and help Ruby/PHP programmer to write inter-communicating widgets without understanding the underlying details.

This is how a widget will be typically developed by Ruby/PHP programmer using NetBeans widget development plugins:

  • right-click and use a wizard to add a new Ruby or PHP widget
  • start writing native Ruby/PHP code
  • right-click and a few selections to deploy the widget
No Java code ever written.

This is how cross-technology widgets will be wired together by Ruby/PHP programmer using NetBeans widget developement plugins:
  • use widget story-board in NetBeans
  • drag-n-drop the widgets (Java/Ruby/PHP) on to the storyboard
  • right-click and add public render parameters (provide a name, thats all)
  • drag-n-connect to wire the widgets together
The only thing that Ruby/PHP developer needs to know is the name of the public render parameter while developing the widget. Everything else is taken care of by the tools.

Thursday Oct 11, 2007

OpenSSO and Liferay Integration Prototype

Introduction
I would prefer to write a short blog and document this somewhere rather than put all of this in a blog, but was not sure where to put it. So this has become a blogument ;)
OpenSSO is an open source project for Single Sign-On. Liferay is an open source portal from Liferay, Inc.
Liferay portal already integrates with CAS single sign-on server. This blogument describes how Liferay portal can be integrated with OpenSSO for single sign-on.

OpenSSO server

  • Download the OpenSSO server
  • For this prototype, FAM 8.0 Build 1 Zip was used. (FAM stands for Federated Access Manager)
  • Turn off the security manager. On Glassfish v2, it is off by default. On AS9.1, access the admin console and turn it off.
  • If security manager needs to be on, then server.policy must be edited as described here. You may need a few more permissions than listed here.
  • Unzip the file and deploy the deployable-war/fam.war as /opensso
  • Access the server (http://opensso-host:port/opensso) to invoke the configurator. Once configured, it will take you to login page where you can login as "amadmin" user.
OpenSSO client
There are 2 ways for an application to leverage OpenSSO as a client
  1. Using client sdk from the downloaded zip (libraries/jars/famclientsdk.jar)
  2. Using web services or REST based services.
There are advantages/disadvantages in both. Client sdk comes with its own cache and a comprehensive set of Java APIs. So you can register SSO token event listners etc. Also you need to configure AMConfig.properties into your classpath.
If you use REST based identity services, then application is responsible for maintaining its own sessions and data cache. But using REST, the client does not have build and runtime dependency on OpenSSO jars. Thanks to Aravindan for providing the info on this latest and greatest feature.

The REST based services were used for this prototype. Currently, only authenticate/authorize/attributes/log are the REST operations available. So there is no way to validate a client session with server or to get a subjectid for an authenticated user. An issue 1079 has been opened with OpenSSO for this enhancement.
For the time being, the subjectid is extracted from the sso cookie and the following REST operation is used,
http://host:port/opensso/identity/attributes?subjectid=ssoTokenId

This returns user details in the following form:
userdetails.token.id=Et2RTHUb+C9TTNipgRqR0MECgg=@AAJTSQACMDE=# userdetails.attribute.name=sn userdetails.attribute.value=user1 userdetails.attribute.name=cn userdetails.attribute.value=user1 userdetails.attribute.name=objectclass userdetails.attribute.value=person userdetails.attribute.value=inetorgperson userdetails.attribute.value=top userdetails.attribute.value=organizationalperson userdetails.attribute.value=inetuser userdetails.attribute.name=employeenumber userdetails.attribute.value=5 userdetails.attribute.name=uid userdetails.attribute.value=user1 userdetails.attribute.name=userpassword userdetails.attribute.value=s9qne0wEqVUbh4HQMZH+CY8yXmc= userdetails.attribute.name=givenname userdetails.attribute.value=user1 userdetails.attribute.name=mail userdetails.attribute.value=user1@fam.com userdetails.attribute.name=inetuserstatus userdetails.attribute.value=Active

It is possible to get this information in the form of xml by using this url:
http://host:port/opensso/identity/xml/attributes?subjectid=ssoTokenId

Authentication filter
First, write an auth filter which redirects a non-authenticated user to the OpenSSO server's login page. An authenticated user is the one who has the sso cookie.
The code is shown below:
package com.liferay.portal.servlet.filters.sso.fam; import java.io.IOException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Cookie; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.FilterChain; public class FAMFilter implements Filter { String loginUrl = null; String logoutUrl = null; String idServicesUrl = null; String ssoCookieName = null; public void init(FilterConfig filterConfig) throws ServletException { loginUrl = filterConfig.getInitParameter("loginUrl"); logoutUrl = filterConfig.getInitParameter("logoutUrl"); ssoCookieName = filterConfig.getInitParameter("ssoCookieName"); } public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // If any of the filter params are null or empty // then skip doing anything because it is misconfig if(loginUrl == null || loginUrl.length() == 0 || logoutUrl == null || logoutUrl.length() == 0 || ssoCookieName == null || ssoCookieName.length() == 0) { chain.doFilter(request, response); } HttpServletRequest httpReq = (HttpServletRequest)request; HttpServletResponse httpRes = (HttpServletResponse)response; String pathInfo = httpReq.getPathInfo(); if (pathInfo != null && pathInfo.indexOf("/portal/logout") != -1) { HttpSession httpSes = httpReq.getSession(); httpSes.invalidate(); httpRes.sendRedirect(logoutUrl); } else { if(isAuthenticated(httpReq)) { chain.doFilter(request, response); } else { httpRes.sendRedirect(loginUrl); } } } private boolean isAuthenticated(HttpServletRequest request) { boolean authenticated = false; Cookie cookie = null; Cookie[] cookies = request.getCookies(); int nCookies = cookies == null ? 0 : cookies.length; for(int i = 0; i < nCookies; i++) { if(ssoCookieName.equalsIgnoreCase(cookies[i].getName())) { cookie = cookies[i]; break; } } if(cookie != null) { authenticated = true; request.getSession().setAttribute("subjectid", cookie.getValue()); } return authenticated; } }

Next add the filter to web.xml:

<filter>
<filter-name>FAM Filter</filter-name>
<filter-class>com.liferay.portal.servlet.filters.sso.fam.FAMFilter</filter-class>
<init-param>
<param-name>logoutUrl</param-name>
<param-value>http://opensso-host:port/opensso/UI/Logout?goto=http://liferay-host:port/</param-value>
</init-param>
<init-param>
<param-name>loginUrl</param-name>
<param-value>http://opensso-host:port/opensso/UI/Login?goto=http://liferay-host:port/</param-value>
</init-param>
<init-param>
<param-name>ssoCookieName</param-name>
<param-value>iPlanetDirectoryPro</param-value>
</init-param>
</filter>


<filter-mapping>
<filter-name>FAM Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Autologin
Now write a FAMAutoLogin class which implements the AutoLogin interface provided by Liferay. This class implements the "login" method of the interface.
In the implementation, it gets the subjectid from the session (which has been stored off by the auth filter).
Then makes a REST call to get the user attribtues.
Liferay needs firstName, lastName, screenName, email for creating a user profile dynamically in its database, if one does not exist. If the authenticated user (from OpenSSO) is not found, then UserLocalServiceUtil is used to add the user to Liferay database.

The source is shown below:
package com.liferay.portal.security.auth; import java.util.Map; import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.liferay.portal.PortalException; import com.liferay.portal.NoSuchUserException; import com.liferay.portal.model.User; import com.liferay.portal.SystemException; import com.liferay.portal.service.UserLocalServiceUtil; import com.liferay.portal.util.PortalUtil; import com.liferay.portal.util.PrefsPropsUtil; import com.liferay.util.PwdGenerator; import com.liferay.util.ldap.LDAPUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.net.URLEncoder; import java.net.URLConnection; import java.io.BufferedReader; import java.net.URL; import java.io.InputStreamReader; import java.io.InputStream; public class FAMAutoLogin implements AutoLogin { public FAMAutoLogin() {} public String[] login(HttpServletRequest req, HttpServletResponse res) throws AutoLoginException { String[] credentials = null; long companyId = PortalUtil.getCompanyId(req); String idServicesUrl = null; try { idServicesUrl = PrefsPropsUtil.getString(companyId, "fam.idservices.url"); } catch(PortalException pe) { throw new AutoLoginException(pe); } catch(SystemException se) { throw new AutoLoginException(se); } String subjectid = (String)req.getSession().getAttribute("subjectid"); if(subjectid == null) { //this should not happen since filter will have already blocked return credentials; } String errorMsg = null; Map nameValues = new HashMap(); String line = null; try { subjectid = URLEncoder.encode(subjectid, "UTF-8"); String url = idServicesUrl + "/attributes?subjectid=" + subjectid; URL iurl = new URL(url); URLConnection connection = iurl.openConnection(); BufferedReader reader = new BufferedReader( new InputStreamReader((InputStream)connection.getContent())); while((line = reader.readLine()) != null) { //each line is returned as x=y String[] parts = line.split("="); //should not happen but we never know if(parts == null || parts.length != 2) { //skip this line continue; } String attrName = null; String attrValue = null; if(parts[0].endsWith("name")) { attrName = parts[1]; //next line must be value line = reader.readLine(); if(line == null) { //something wrong - name must be followed by value throw new AutoLoginException( "Error reading user attributes"); } //each line is returned as x=y parts = line.split("="); //should not happen but we never know if(parts == null || parts.length != 2 || !parts[0].endsWith("value")) { attrValue = null; } else { attrValue = parts[1]; } nameValues.put(attrName, attrValue); } } } catch(java.io.UnsupportedEncodingException use) { throw new AutoLoginException(use); } catch(java.net.MalformedURLException me) { throw new AutoLoginException(me); } catch(java.io.IOException ioe) { throw new AutoLoginException(ioe); } //Liferay user must have these attrs String firstName = (String)nameValues.get("cn"); String lastName = (String)nameValues.get("sn"); String screenName = (String)nameValues.get("givenname"); String email = (String)nameValues.get("mail"); if(email == null || email.length() == 0) { throw new AutoLoginException("No email set for user"); } User user = null; try { user = UserLocalServiceUtil.getUserByEmailAddress(companyId, email); } catch(NoSuchUserException nsue) { try { user = addUser(companyId, screenName, firstName, lastName, email); } catch(Exception e) { throw new AutoLoginException(e); } } catch(Exception e) { throw new AutoLoginException(e); } credentials = new String[3]; credentials[0] = String.valueOf(user.getUserId()); credentials[1] = user.getPassword(); credentials[2] = Boolean.TRUE.toString(); return credentials; } protected User addUser(long companyId, String screenName, String firstName, String lastName, String email) throws PortalException, SystemException { long creatorUserId = UserLocalServiceUtil.getDefaultUserId(companyId); User user = null; try { user = UserLocalServiceUtil.addUser(creatorUserId, companyId, true, "", "", false, screenName, email, java.util.Locale.ENGLISH, firstName, "", lastName, 0, 0, true, 1, 1, 1970, "", 0, 0, false); } catch (Exception e){ _log.error( "Problem adding user with screen name " + screenName + " and email address " + email, e); } return user; } private static Log _log = LogFactory.getLog(FAMAutoLogin.class); }

Liferay Hooks
Liferay portal provides hooks to plugin auto login classes.
Edit (or create if one does not exist in the deployment) portal-ext.properties and add the following:
auto.login.hooks=com.liferay.portal.security.auth.FAMAutoLogin,com.liferay.portal.security.auth.CASAutoLogin,com.liferay.portal.security.auth.NtlmAutoLogin,com.liferay.portal.security.auth.OpenIdAutoLogin,com.liferay.portal.security.auth.RememberMeAutoLogin fam.idservices.url=http://opessso-host:port/opensso/identity

Testing
  1. Access http://opensso-host:port/opensso/
  2. Login as amadmin
  3. Click on the root realm and goto Subjects tab
  4. Add a new user
  5. Now click on the new user's name to edit user profile
  6. Enter an email for the new user (this is important since Liferay needs email)
  7. Logout from OpenSSO and try login as the new user to verify
  8. Access Liferay portal to be redirected to OpenSSO login page
  9. Login as the new user to be redirected back to Liferay portal
  10. Accept the terms and conditions (first time only) to see the Liferay portal pages
Conclusion
The prototype demonstrates how Liferay can be integrated to leverage OpenSSO. For production, use of client sdk may be considered. Liferay can also integrate with LDAP and import membership information. OpenSSO can integrate with various user repositories, so similar implementation can be provided to import membership from OpenSSO user repositories. Even more desirable scenario would be if Liferay can fetch membership at runtime instead of importing it to a local datastore and then struggling to keep it in sync with corporate user repository. The auth filter can be further enhanced to allow anonymous/guest access and then writing an OpenSSO login portlet.

References
  1. Setting_up the Extension Environment
  2. Integrating Liferay With CAS
  3. Developing a Custom Authentication System
  4. Liferay LDAP integration
  5. OpenSSO project page

Tuesday Jul 24, 2007

Debugging Portal - Dynamic Service Attributes


Portal Server (PS) uses Access Manager (AM) features which in turn uses Directory Server (SunDS) features. One of such features of SunDS is Class Of Service or COS which is used by AM in Service Management System (SMS).
Portal defines services and registers these services into AM.
Some services are shared by multiple portals while some services are portal specific.
Shared services are:
    Rewriter
    SSO Adapter
    All Sercure Remote Access (SRA) related services

Portal specific services are shown below and have their names mangled with portal-id
    Desktop - SunPortalmyPortalDesktopService
    Subscriptions - SunPortal
myPortalSubscriptionsService

Most of these services use "Dynamic" type of attributes which are stored by AM using the COS feature. It means that these are virtual attributes and are not set at the node, but set into the COS template.
Many times we come across a situation while debugging portal, when we want to see the the value of such a COS attribute at a specific node. Looking at the node does not tell us if the value is set at the node or the value is being inherited.

For example, running the following query on a user shows this:

/opt/SUNWam/bin> ./ldapsearch -b 'o=EnterpriseSample,dc=red,dc=iplanet,dc=com'
-D "cn=Directory Manager" -w 11111111 "cn=u1"

version: 1
dn: uid=u1,ou=People,o=EnterpriseSample,dc=red,dc=iplanet,dc=com
sn: u1
cn: u1
uid: u1
...
sunPortalmyPortalDesktopCommunityCreateContainerName: CommunityCreatePortlet
sunPortalmyPortalDesktopCommunityHomeContainerName: CommunityHomeContainer
sunPortalmyPortalDesktopDefaultChannelName: JSPTabContainer
sunPortalmyPortalDesktopEditProviderContainerName: JSPEditContainer
sunPortalmyPortalDesktopType: enterprise_sample
sunPortalmyPortalMaxCategorySubscriptions: 5
sunPortalmyPortalMaxDiscussionSubscriptions: 5
sunPortalmyPortalMaxSavedSearch: 5

The COS feature of SunDS gives the attribute value as sunPortalmyPortalDesktopType=enterprise_sample which in this case is inherited from the parent organization.
If the user belongs to different roles, then it becomes even more complex to track down where the value is being inherited because it will be resolved using COS priority and if the priority is same then the value is indeterministic.

One easy way is to execute an ldapsearch like this and then parse through the dump to locate the template attribtues. This gets a bit cumbersome with a huge dump.

/opt/SUNWam/bin> ./ldapsearch -b 'o=EnterpriseSample,dc=red,dc=iplanet,dc=com'
-D "cn=Directory Manager" -w 11111111 "(objectclass=*)"

Another easier way is to run a search on individual node templates.

To see the attribtues set for the organization template for desktop service, execute the search shown below. Notice that the base dn always has cn=ContainerDefaultTemplateRole for an organization and the name of the service is mangled with portal-id.

/opt/SUNWam/bin>./ldapsearch -b
'cn="cn=ContainerDefaultTemplateRole,o=EnterpriseSample,dc=red,dc=iplanet,dc=com",
cn=SunPortalmyPortalDesktopService,o=EnterpriseSample,dc=red,dc=iplanet,dc=com'
-D "cn=Directory Manager" -w 11111111 "(objectclass=*)"


version: 1
dn: cn="cn=ContainerDefaultTemplateRole,o=EnterpriseSample,..."
cn: cn=ContainerDefaultTemplateRole,o=EnterpriseSample,dc=red,dc=iplanet,dc=com
objectClass: costemplate
objectClass: top
objectClass: extensibleObject
sunPortalmyPortalDesktopEditProviderContainerName: JSPEditContainer
sunportaldesktopdpcanview: true
cosPriority: 0
sunportaldesktopdpdocument:: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgi
IHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBEaXNwbGF5UHJvZmlsZSBTWVNURU0gImphcjov
...
...

ZSIgbG9jaz0iZmFsc2UiIG1lcmdlPSJmdXNlIiBuYW1lPSJfcm9vdCIgcHJpb3JpdHk9IjEwIiB2
sunportaldesktopdplastmodified: 1184692202155
sunPortalmyPortalDesktopCommunityHomeContainerName: CommunityHomeContainer
sunPortalmyPortalDesktopDefaultChannelName: JSPTabContainer
sunPortalmyPortalDesktopCommunityCreateContainerName: CommunityCreatePortlet
sunPortalmyPortalDesktopType: enterprise_sample

To look at the role nodes, following search can be used. Notice here that the base dn starts with cn="cn=RoleName... and also has portal qualified desktop service name.

/opt/SUNWam/bin> ./ldapsearch -b 'cn="cn=AustraliaExpansionRole,o=EnterpriseSample,dc=red,dc=iplanet,dc=com",
cn=SunPortalmyPortalDesktopService,o=EnterpriseSample,dc=red,dc=iplanet,dc=com'

-D "cn=Directory Manager"
-w 11111111 "(objectclass=*)"


version: 1
dn:
cn="cn=AustraliaExpansionRole,o=EnterpriseSample,dc=red,dc=iplanet,dc=com"
,cn=SunPortalmyPortalDesktopService,o=EnterpriseSample,dc=red,dc=iplanet,dc=
com
cn: "cn=AustraliaExpansionRole,o=EnterpriseSample,dc=red,dc=iplanet,dc=com"
cn: cn=AustraliaExpansionRole,o=EnterpriseSample,dc=red,dc=iplanet,dc=com
objectClass: costemplate
objectClass: top
objectClass: extensibleObject
sunPortalmyPortalDesktopEditProviderContainerName: JSPEditContainer
sunportaldesktopdpcanview: true
cosPriority: 0
sunPortalmyPortalDesktopDefaultChannelName: JSPTabContainer
sunPortalmyPortalDesktopType: enterprise_sample
sunportaldesktopdpdocument:: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgi
IHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBEaXNwbGF5UHJvZmlsZSBTWVNURU0gImphcjov
...
...
dmlkZXJzPgogICAgPC9Qcm92aWRlcnM+CjwvRGlzcGxheVByb2ZpbGU+Cg==
sunportaldesktopdplastmodified: 1184692031309

And the easiest way is of course using an ldapbrowser.
First select the organization node in the Explore tab on the left and then set the quick search bar to
"cn=ContainerDefaultTemplateRole,o=EnterpriseSample,dc=red,dc=iplanet,dc=com"
and click "Quick Search"


Then select the ContainerDefaultTemplateRole under a service in Results tab, to see the dynamic service attributes set for the organization, on the right.

 

Change the name from ContainerDefaultTemplateRole to any other role name to see dynamic attributes at the role node.

Happy Debugging...

Calendar

Feeds

Search

Links

Navigation

Referrers