Skip to main content

Securing Java applications with Acegi, Part 3: Access control for Java objects

Use method-based security to protect Java class instances

Bilal Siddiqui , Freelance consultant, WaxSys
Bilal Siddiqui is an electronics engineer, an XML consultant, and the co-founder of WaxSys, a company focused on simplifying e-business. After graduating in 1995 with a degree in electronics engineering from the University of Engineering and Technology, Lahore, he began designing software solutions for industrial control systems. Later, he turned to XML and used his experience programming in C++ to build Web- and Wap-based XML processing tools, server-side parsing solutions, and service applications. Bilal is a technology evangelist and a frequently-published technical author.

Summary:  Bilal Siddiqui continues his introduction to Acegi Security System by showing you how to secure access to instances of your Java™ classes. Learn why you need to secure access to your Java classes, how Spring creates and secures instances of your Java classes, and how to configure Acegi to incorporate class security in your Java applications.

View more content in this series

Date:  25 Sep 2007
Level:  Introductory PDF:  A4 and Letter (103KB | 9 pages)Get Adobe® Reader®
Activity:  6543 views

This series of articles is an introduction to using Acegi Security System to secure Java enterprise applications. Part 1 of this series introduced Acegi and explained how to use its built-in security filters to implement a simple, URL-based security system. Part 2 showed you how to write an access control policy and store it in an LDAP directory server, as well as how to configure Acegi to interact with the directory server to implement your access control policy. This third article in the series demonstrates how to use Acegi to secure access to Java class instances in your enterprise applications.

I'll start by briefly explaining when you might need to secure access to your Java classes, including a couple of typical enterprise application scenarios for reference. For further background, I explain how Spring's inversion of control (IOC) framework creates instances of Java classes, which are accessible from your JSPs or servlets. I also introduce the important concept of bean proxies, which Spring uses to filter access to Java objects. Finally, I will show you how to configure Acegi's method security interceptor to control access to your Java classes. I continue with this article in the series by enhancing the sample application from Part 2 to incorporate support for secure Java objects.

Because this discussion builds on the previous two articles in the series, I frequently reference the discussion and examples from Part 1 and Part 2. It may be helpful to open these installments in additional browser windows before you continue.

Use cases for securing Java classes

You might recall that I talked briefly about enterprise application security at the beginning of this series. In that introductory discussion, I mentioned a scenario in which URL security would not be enough:

Consider a PDF document containing the data about a particular product manufactured by the manufacturing company. Part of the document contains design data meant to be edited and updated by the company's design department. Another part of the document contains production data, which production managers will use. For a scenario like this one, you would need to implement more fine-grained security applying different access rights to different portions of the document.

Before moving on, let's consider a couple more application scenarios that might require you to secure individual classes in addition to implementing URL security.

Business automation

Workflows in business automation applications consist of processes. For example, the workflow of performing a blood test in a pathology laboratory could consist of a number of steps, with each step being considered a business process:

  1. A staff member collects the blood sample from a patient and assigns an ID number to the sample.
  2. A laboratory technician performs the required test on the sample and prepares the test results.
  3. A qualified pathologist writes a test report based on the prepared test results.

You can clearly see that each process is executed by a separate user who is authorized to execute the process. Someone who is not authorized to perform a process should not be able to execute the process. For example, the lab technician should only prepare test results and should not be able to write the test report.

Authorized business processes are common to almost all business automation applications. Normally, you would implement each business process as a Java class, and all the classes would need to be secured by means of an appropriate access control policy.

Business-to-business integration

Business-to-business (B2B) integration refers to the common scenario where two business entities need to expose specific functionality to each other. For example, a hotel might expose its room reservation functionality to a tour operator, who could then use it to reserve an available hotel room for a tourist. As a partner, the tour operator might also have a special room reservation rate. In this case, the hotel's reservation system would have to authenticate the operator before allowing access to the selected classes for reserving rooms at the special rate.


Creating Java objects in Spring

Now you have an idea of why it's important to be able to secure access to Java class instances. Before introducing Acegi's functionality for this advanced level of security, I want to refresh your memory about some of the key features of the Spring framework, which you need to understand to follow the upcoming examples.

Let's start by configuring some Java classes and instantiating them. As you might recall from Part 1, Java classes are configured in Spring's XML configuration file. Configuring a Java class in a Spring configuration file is exactly the same as configuring an Acegi filter, so I won't explain this step. Instead, just take a look at Listing 1, which shows the configuration for a bean named publicCatalog:


Listing 1. Acegi XML configuration file
<beans>
    <bean id="publicCatalog" 
       class="com.catalog.PublicCatalog" />
    <!--Other bean tags -->
<beans>

It's important that you understand how Spring's IOC framework reads information about your Java classes from the XML configuration file and instantiates them. You might recall that in the first article of this series, I used a web.xml file to configure a <listener> tag pointing to a class named ContextLoaderListener. The ContextLoaderListener loads Spring's IOC framework and creates Java objects. You can see all this by referring back to Part 1, Listing 8. It is also depicted in Figure 1:


Figure 1. Loading Spring's IOC framework and creating Java objects
Steps to load Spring's IOC framework and create Java objects

Now let's consider those steps in detail:

  1. When you initiate your Acegi application, the servlet container (in this case Apache Tomcat) creates a servlet context, which holds information about application resources such as JSP pages and classes.

  2. The servlet container notifies the ContextLoaderListener class that your application is being started.

  3. The ContextLoaderListener class creates a Web application context to hold information about the Spring-specific resources of your application. With the Spring's IOC framework, you can load your own custom application context. To create an application context, it uses a context loader class named ContextLoader, which loads the application context.

  4. In case the application does not want to define its own application context, it can use a class named XMLWebApplicationContext, which is part of the Spring framework and provides functionality to process Spring's XML configuration files. Acegi applications use Spring's XML configuration file, so this article discusses only the application context represented by the XMLWebApplicationContext class. In the case of this example, the context loader instantiates the XMLWebApplicationContext class, which represents the application context for your Acegi application. The context loader also sets a reference of the servlet context (created in Step 1) into the Web application context.

  5. The XMLWebApplicationContext class parses your XML configuration file for information about your Java classes and loads the information into its internal objects.

  6. The XMLWebApplicationContext class instantiates all the Java classes specified in your XML configuration file. The XMLWebApplicationContext class checks whether a Java bean configured in the XML configuration file depends on some other Java objects. If so, the XMLWebApplicationContext class first instantiates the beans on which other beans depend. In this way, the XMLWebApplicationContext class creates instances of all the beans defined in the XML configuration file. (Note that Step 6 assumes that none of the beans configured in the XML configuration file need to be secured. A later section explains the additional steps that have occurred between Step 5 and Step 6 to secure access to Java beans created here.)

  7. The XMLWebApplicationContext class stores all beans in an array.

You've seen how to load bean definitions from an XML configuration file and create instances of Java classes. Next, I'll introduce you to the Spring bean proxy and explain its importance when securing access to Java class instances.


Using bean proxies

The previous section discussed how Spring's IOC framework instantiates Java objects. In order to secure access to your Java objects, Spring's IOC framework uses the concept of bean proxies. This section first shows you how to configure a bean proxy and then demonstrates how Spring's IOC framework creates the proxy object.

Configuring a proxy for a Java object

If you want to create a proxy bean, the Spring IOC framework requires you to configure an instance of a proxy creator bean. Spring's IOC framework uses the proxy creator to create proxy objects. Listing 2 is the configuration file for the proxy creator bean, used to secure a Java object named privateCatalog:


Listing 2. Proxy bean configuration
<bean id="proxyCreator"
   class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
      <list>
        <value>privateCatalog</value>
        <!--Names of other beans to be proxied -->
      </list>
    </property>
    <property name="interceptorNames">
      <list>
         <value>privateCatalogSecurityInterceptor</value>
       </list>
    </property>
</bean>

As you can see in Listing 2, the <bean> tag has a class attribute whose value is org.springframework.aop.framework.autoproxy. BeanNameAutoProxyCreator. The BeanNameAutoProxyCreator class is part of the Spring IOC framework and automatically creates bean proxies. The Spring framework provides an interface named BeanPostProcessor, which represents an extensibility mechanism to allow applications to write their own logic to create bean proxies. Spring's BeanNameAutoProxyCreator class implements the BeanPostProcessor interface and provides all the proxy creation logic that you need to secure your Java classes. Therefore, you don't need to implement the BeanPostProcessor interface for the purpose of this article.

While creating bean proxies, the BeanNameAutoProxyCreator class creates proxies for all the beans defined by the beanNames property (see the first <property> child of the <bean> tag in Listing 2). The beanNames property takes a list of bean names in a <list> tag. In Listing 2, I have configured only one bean named privateCatalog for which I want to create a proxy.

Now look at the second <property> child of the <bean> tag in Listing 2. It specifies a property named interceptorNames, which wraps the names of one or more interceptors. I will discuss the concept of interceptors in detail later in the article. For the moment, just note that an interceptor can intercept a user's request and implement an access control policy before allowing the user to access the bean.

Now you've seen how to configure proxy for the beans that you want to protect. Next, you'll learn how Spring's IOC framework internally creates proxy objects for the beans of your application.

Spring IOC takes over

In Step 5 and Step 6 of "Creating Java objects in Spring" you saw how the XMLWebApplicationContext class reads bean definitions from an XML configuration file and then creates bean instances. Before creating a bean instance, the XMLWebApplicationContext class checks whether the XML configuration file contains any proxy creator bean configuration (that is, a bean that implements the BeanPostProcessor interface). If it finds one, it asks the proxy creator to create bean proxies for the beans that you wish to secure.

Now consider how the proxy creator internally creates proxy objects:

  1. The proxy creator (that is, the BeanNameAutoProxyCreator class) loads all the bean names specified in the beanNames property file that you configured in Listing 2.

  2. The proxy creator uses the bean names to load their respective Java classes using the class attribute of each bean definition.

  3. The proxy creator creates an instance of the interceptor specified in the interceptorNames property shown in Listing 2.

  4. Finally, the proxy creator creates an instance of a class named Cglib2AopProxy, passing all the bean names (from Step 2) and the interceptor (from Step 3) to the Cglib2AopProxy class. The Cglib2AopProxy class is part of the Spring framework and is used to generate dynamic proxy objects. In this case, the Cglib2AopProxy class creates the proxy objects you will need to control access to your secure beans.

The Cglib2AopProxy class implements two interfaces named AOPProxy and MethodInterceptor. The AOPProxy interface is part of the Spring framework and represents the actual bean that you want to proxy, so it exposes the same methods that your bean exposes. The MethodInterceptor interface, also part of the AOP specification, has methods that receive control whenever a user tries to access the bean that you have proxied. This means the MethodInterceptor interface handles requests from users to access a proxied bean. Given that the Cglib2AopProxy class implements both AOPProxy and MethodInterceptor interfaces, you can guess that it offers the complete functionality of representing a proxied bean as well as handling user requests to access a proxied bean. (See the Resources section for links to articles that discuss AOP.)

After executing the previous steps, you have the required proxy objects. So the XMLWebApplicationContext class stores the proxies of secure beans (instead of the actual beans) in the same array that you saw in Step 7 of "Creating Java objects in Spring."


Accessing proxied Java objects

In the previous sections, you learned how Spring creates public beans and private beans. For the purpose of this article, you can think of public beans as unsecured and private ones as being secured by proxy. Now let's look at the sequence of steps a client application must follow to access public and private beans.

Listing 3 shows the XML configurations for two beans named publicCatalog and privateCatalog. The publicCatalog bean is meant for public access so it does not need a bean proxy. The privateCatalog bean is meant to be accessed only by designated users, so it must be secured. I have included a bean proxy configuration for the privateCatalog bean in Listing 3:


Listing 3. XML configuration for publicCatalog and privateCatalog beans
<beans>
  <bean id="publicCatalog" class="sample.PublicCatalog"/>
  <bean id="privateCatalog" class="sample.PrivateCatalog"/>

  <!-- proxy configuration for privateCatalog bean -->
  <bean id="proxyCreator"
    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
      <list>
        <value>privateCatalog</value>
        <!--Names of other beans to be proxied -->
      </list>
    </property>    
    <property name="interceptorNames">
      <list>
         <value>privateCatalogSecurityInterceptor</value>
       </list>
    </property>
  </bean>
<beans>

Listing 4 shows the code that an application could use to access the publicCatalog and privateCatalog Java beans configured in Listing 3. Note that the Java code shown in Listing 4 could exist in a JSP page or in another bean contributing to a server-side Java application.


Listing 4. Client application code to access secure and insecure Java beans
 
//Step 1: Fetching an instance of the application context
XMLWebApplicationContext applicationCtx =
    WebApplicationContextUtils.getWebApplicationContext(
        this.getServletConfig().getServletContext());

//Step 2: Fetching an insecure bean from the application context
PublicCatalog publicCatalog = 
    (PublicCatalog) applicationCtx.getBean("publicCatalog");

//Step 3: Calling a method of the insecure bean
String publicData = publicCatalog.getData();

//Step 4: Fetching a secure bean from the application context
PrivateCatalog privateCatalog = 
    (PrivateCatalog) applicationCtx.getBean("privateCatalog");

//Step 5: Calling a method of the secure bean
String privateData = privateCatalog.getData();

Consider the steps in Listing 4 in greater detail:

  • Step 1: Fetching an instance of the application context
    When an application wants to access a Java bean configured in an XML configuration file, it has to fetch the XMLWebApplicationContext object that you saw earlier in Step 4 of "Creating Java objects in Spring." The XMLWebApplicationContext object contains references to all the Java beans configured in the XML configuration file.

  • Step 2: Fetching an insecure bean from the application context
    You now have a reference to the XMLWebApplicationContext object. The XMLWebApplicationContext class exposes a method named getBean(), which takes the name of a bean and finds the bean in the array it prepared in Step 7 of "Creating Java objects in Spring." In this case, the bean is publicCatalog (which is not proxied), so the XMLWebApplicationContext returns the actual bean.

  • Step 3: Calling a method of the insecure bean
    Now you can call any method of the publicCatalog bean you got in Step 2. For example, the getData() method call shown in Listing 4 executes without any access control and returns the catalog data to the application.

  • Step 4: Fetching a secure bean from the application context
    Fetching a secure bean is similar to fetching insecure beans. The only difference is that when you try to fetch a secure bean by calling the getBean() method, you get a proxy of the secure object instead of the actual object. The proxy is the same object created by the Spring framework that I explained in Step 4 of "Spring IOC takes over."

  • Step 5: Calling a method of the secure bean
    When you call a method of a secure bean, the proxy object that you got in Step 4 dispatches a method invocation request to the interceptor. The interceptor processes the method invocation request by checking if the user trying to access the method has appropriate access rights.

You should have a clear picture now of how the Spring framework creates Java objects and how client applications interact with them. With this background, it will be easier to understand and utilize Acegi's method security interceptor, which is the topic of the next section.


Configuring Acegi's method security interceptor

Whenever an application tries to access a method of a bean secured using Acegi Security System, the request is automatically transferred to Acegi's method security interceptor. The purpose of the method security interceptor is to control access to methods of secure Java beans. The interceptor uses Acegi's authentication and authorization framework to confirm whether a user is authorized to call a method of the secure Java bean, and then responds accordingly.

Listing 5 is a sample configuration of Acegi's method security interceptor:


Listing 5. Configuration of Acegi's method security interceptor
 
<bean id="privateCatalogSecurityInterceptor"
  class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
  <property name="authenticationManager">
     <ref bean="authenticationManager"/>    
  </property>
  <property name="accessDecisionManager">
     <ref bean="accessDecisionManager"/>
  </property>
  <property name="objectDefinitionSource">
    <value>
      sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING
      <!-- Roles required by other beans -->
    </value>
  </property>
</bean>

The interceptor configuration shown in Listing 5 contains three properties that you need to configure in order to secure access to your Java beans: authenticationManager, accessDecisionManager, and objectDefinitionSource.

Recall that you configured the authenticationManager property while configuring the authentication processing filter in the first article of this series. The purpose of the authenticationManager property is to authenticate a user.

You learned about the accessDecisionManager property in the second article in this series. The access decision manager is responsible for making authorization decisions. The method security interceptor uses the authenticationManager and accessDecisionManager properties to authenticate and authorize a user before allowing access to a secure bean.

Now look at the objectDefinitionSource property configured in Listing 5. It is similar to the objectDefinitionSource property shown in Part 1. Whereas the original objectDefinitionSource contained URLs like /protected/* and /**, the objectDefinitionSource property in Listing 5 specifies class and method names; for instance, sample.PrivateCatalog is the name of a class that you proxied earlier and getData is the name of a method to which you want to control user's access.

Whenever the user accesses the getData() method of the PrivateCatalog bean, control is automatically transferred to the interceptor. The interceptor uses the Acegi framework to check whether the user's business role is ROLE_HEAD_OF_ENGINEERING (in this example). If it is, the interceptor allows access to the getData() method. If interceptor finds that the user does not have the ROLE_HEAD_OF_ENGINEERING, it denies access.

The next section looks at a sample Acegi application that implements the concepts you have learned so far.


A sample Acegi application

The source code download for this article contains a sample application called AcegiMethodSecurity, which you can configure and deploy as follows:

  1. Populate your LDAP server with user information. The sample application download contains an LDIF file that has user information ready to be loaded into your LDAP server. See "Populating the server" in Part 2 for a refresher on importing the LDIF file into your LDAP server. Note that this application features the same users (alice, bob, and specialUser) that you worked with in Part 2.

  2. Copy the acegiMethodSecurity.war file from the source code download of this article into the webapps directory of your Tomcat installation.

  3. Copy Acegi's jar files into the WEB-INF/lib folder of the sample application. (See "Deploy and run the application" from Part 1 for a refresher on this.)

  4. Download the cglib-full-2.0.2.jar file and copy it in WEB-INF/lib folder of the sample application.

Start Tomcat and you should be all set to try the sample application.

Get to know the sample application

You can invoke the sample application by accessing the http://localhost:8080/acegiMethodSecurity URL from your browser. The AcegiMethodSecurity application displays an index page that contains two links (Catalog and Login), as shown in Figure 2:


Figure 2. Main page of the sample application
Main page of the sample application

When you click on the application's Catalog link, it will ask you to log in. If you log in as alice or specialUser, the sample application serves you the complete catalog, including both public and private data. That's because back in Listing 5, you configured the method security interceptor to allow users having ROLE_HEAD_OF_ENGINEERING to access the private catalog, and both alice and specialUser have that access. On the other hand, if you log in as bob, the sample application shows you only public data.


Assigning additional roles to authenticated users

This section demonstrates an enhanced version of the sample application. The enhanced version shows how Acegi lets you temporarily assign additional roles to an authenticated user at runtime.

You might need additional roles whenever a secure bean (such as the privateCatalog bean of Listing 3) needs to access a remote resource. As an example, you might consider that your secure bean needs to access a remote application through Java's Remote Method Invocation (RMI) framework or a Web service. The user accessing your secure bean will not possess the business role that the remote application expects from a user trying to access it.

In this case, Acegi first checks whether the user is authorized to access the secure bean. After checking, Acegi allows the user to access the secure bean. When the secure bean attempts to access the remote service, it will need additional business roles. If the user who accessed the secure bean does not have the additional role(s), the secure bean will not be able to successfully access the remote service.

The run-as-replacement mechanism

The Acegi framework provides a simple mechanism called run-as-replacement that allows you to configure one or more additional roles for an authenticated user only for the duration of a method invocation call. You can use the run-as replacement to configure additional roles for a secure bean to access remote applications. This means whenever the secure bean needs to access a remote application, Acegi will load additional roles for the user, thus allowing the secure bean to access the remote application.

Listing 6 shows an enhanced configuration of the method security interceptor that you saw earlier in Listing 5. The enhanced version uses the run-as-replacement mechanism.


Listing 6. Enhanced configuration of Acegi's method security interceptor
 
<bean id="privateCatalogSecurityInterceptor"
  class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
  <property name="authenticationManager">
     <ref bean="authenticationManager"/>    
  </property>
  <property name="accessDecisionManager">
     <ref bean="accessDecisionManager"/>
  </property>
  <property name="runAsManager">
<bean id="runAsManager" class="org.acegisecurity.runas.RunAsManagerImpl">
<property name="key"> <value>myKeyPass</value> </property> </bean> </property> <property name="objectDefinitionSource"> <value> sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING,RUN_AS_MANAGER </value> </property> </bean>

You can see two enhancements in Listing 6 (as compared to Listing 5) shown in bold. The first enhancement is a property named runAsManager. The purpose of the runAsManager property is to add support for dynamically adding roles to the authenticated user. For this purpose, the runAsManager property contains the definition of a bean named RunAsManagerImpl. The RunAsManagerImpl bean becomes active only when it finds a role with RUN_AS_ prefix in the role definitions of a method in objectDefinitionSource. For example, the role definition of the PrivateCatalog.getData() method (the second bold enhancement in Listing 6) has a RUN_AS_MANAGER role.

The RunAsManagerImpl bean contains a property named key, which wraps a cryptographic key used to ensure that the additional role can only be generated as part of the run-as-replacement procedure.

When a user calls the getData() method, the RunAsManagerImpl bean becomes active and creates an additional role named RUN_AS_MANAGER, thus enabling the getData() method to access the remote application.

Enhanced method security

This article's source code download includes a sample application named EnhancedAcegiMethodSecurity, which demonstrates the run-as-replacement mechanism and procedure. The application displays an index page with a Catalog link. If you click the Catalog link, you will be asked to log in.

Once you have logged in, the EnhancedAcegiMethodSecurity application will provide you with the complete information about the logged-in user and that user's roles. For instance, if you log in as alice or specialUser, you will be shown all the business roles of the user including the additional temporary RUN_AS_MANAGER role.

Conclusion

In this series of articles, I introduced you to using Acegi Security System to enforce both URL-based security and method-based security. You learned how to design access control policies and host them in a directory server, how to configure Acegi to communicate with a directory service, and how to make authentication and authorization decisions based on the access control policies hosted there.

This article focused on using method-based security to protect Java class instances. It also explained how Acegi and Spring internally create and proxy Java objects and how bean proxies work to implement access control. The article includes a couple of sample applications that you can use to further explore the concepts you have learned in this series. See the Resources section to learn more about securing Java applications with Acegi.



Download

DescriptionNameSizeDownload method
Source code for this articlej-acegi3-source.zip36KB HTTP

Information about download methods


Resources

Learn

Discuss

About the author

Bilal Siddiqui is an electronics engineer, an XML consultant, and the co-founder of WaxSys, a company focused on simplifying e-business. After graduating in 1995 with a degree in electronics engineering from the University of Engineering and Technology, Lahore, he began designing software solutions for industrial control systems. Later, he turned to XML and used his experience programming in C++ to build Web- and Wap-based XML processing tools, server-side parsing solutions, and service applications. Bilal is a technology evangelist and a frequently-published technical author.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=257811
ArticleTitle=Securing Java applications with Acegi, Part 3: Access control for Java objects
publish-date=09252007
author1-email=bsiddiqui@xml4java.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers