Firewall config for Java Web App hosted on AWS EC2 Windows 2012 server

According to AWS documentation, creating the right security group configuration should be sufficient to allow for desired communication between your AWS EC2 instance and public internet. However, that’s not quite the case when you provision a Microsoft Windows 2012 VM as an EC2 instance.

I provisioned a windows 2012 EC2 instance and opened the following ports on it (Security Group Configuration Image below).

  • Port 80 for HTTP communication
  • Port 3389 for RDP communication
  • Port 443 for HTTPS communication
  • Port 8080 for TCP communication over port 8080. This was primarily because my Java app was a Liferay web app which comes bundled together with Tomcat 8 server and deploys to port 8080 by default. You can modify server.xml to change this port.

Configure Security Group of AWS EC2 Instance

After configuring the security group settings above and provisioning the EC2 instance, I needed to be able to access a very basic web app deployed on a Tomcat 8 server from the public internet. Navigating to http://localhost:8080 worked fine from within the Windows VM, however, if I accessed http://<vm-public- ip-address>:8080 from my web browser on the public internet I was not able to navigate to the app.

Turns out the only way to fix this is to modify the windows firewall rules on the VM in addition to the security group configurations above.

To modify the firewall rules on your windows server:

  1. Navigate to Control Panel -> System and Security -> Windows Firewall
  2. Click on Advanced Settings. This should open Windows Firewall with Advanced Security windows.
Windows 2012 Firewall Rules wizard

Windows 2012 Firewall Rules wizard

  • Click on Inbound Rules. This should display all the inbound rules for the firewall on the server.
  • Click on New Rule… This should open ‘New Inbound Rule Wizard’.
  • Select ‘Port’ radio button -> Click Next -> Enter 8080, 80, 443 in ‘Specific local ports’ -> Click Next -> Select ‘allow the connection’ -> Click Next -> Click Next -> Enter “Custom Inbound rules” under Name -> Click Finish.

pic3

  • If you try to access your app web app from the public network, you should be able to access it.

Liferay LDAP Export to Active Directory disabled user bug.

Liferay 6.1 LDAP tool has a bug where the Liferay user is exported into Active Directory but is disabled by default. After much deliberation I found a workaround where we can write a hook to export users instead of using the out of the box tool. The hook uses a Model Listener on the User Model to look for changes to the user object i.e. the custom code is triggered when anything about the User object changes. The custom code uses the Java JNDI interface to create and or update users in Active Directory.

	@Override
	public void onAfterCreate(User user) throws ModelListenerException {
		LDAPUtil util = new LDAPUtil();	

				try {
					log.info("Attempting to create user: Screen Name: "
							+ user.getScreenName() + " :First Name: "
							+ user.getFirstName() + " : LastName: "
							+ user.getLastName() + " Email:"
							+ user.getEmailAddress()+ " OpenID: "
					+ user.getOpenId()+ " JobTitle: "
					+ user.getJobTitle());
					util.createAdUser(user.getScreenName(),
							user.getPasswordUnencrypted(), user.getFirstName(),
							user.getLastName(), user.getEmailAddress(),
							user.getOpenId(), user.getJobTitle());

				} catch (Exception e) {
					e.printStackTrace();
					throw new ModelListenerException(e);
				}
	}

 	public void createAdUser(String screenName, String password, String firstName, String lastName, String emailAddress, String openID, String jobTitle) {
		try {

			// Create the initial directory context
			LdapContext ctx = getLdapContext();
			String userDn = getUserDN(screenName);

			// Create attributes to be associated with the new user
			Attributes attrs = new BasicAttributes(true);

			// These are the mandatory attributes for a user object
			// Note that Win2K3 will automagically create a random
			// samAccountName if it is not present. (Win2K does not)
			List<String> objectClasses =  Arrays.asList(PropsUtil.get("your.object.classes").split(","));
			for (String objectClass: objectClasses){
				attrs.put("objectClass", objectClass);
			}
			//attrs.put("samAccountName", screenName);
			
			attrs.put("cn", screenName);
			attrs.put("mail", emailAddress);
			// These are some optional (but useful) attributes
			attrs.put("givenName",firstName);
			attrs.put("sn", lastName);
			attrs.put("displayName", screenName);
			if (openID != null && openID.trim().length() > 0){
				log.info("AD User: Setting emplyeeID to: "+openID);
				attrs.put("employeeID", openID);
			}
			if (jobTitle != null && jobTitle.trim().length() > 0){
				log.info("AD User: Setting emplyeeNumber to: "+openID);
				attrs.put("employeeNumber", jobTitle);
			}
			//attrs.put("userPrincipalName", username);

			// Note that the user object must be created before the password
			// can be set. Therefore as the user is created with no
			// password, userAccountControl must be set to the following
			// otherwise the Win2K3 password filter will return error 53
			// unwilling to perform.
			attrs.put("userAccountControl", Integer.toString(UF_NORMAL_ACCOUNT + UF_PASSWD_NOTREQD + UF_PASSWORD_EXPIRED + UF_ACCOUNTDISABLE));
			log.info("Creating AD user: " + userDn);
			// Create the context
			Context result = ctx.createSubcontext(userDn, attrs);
			log.info("Created account: " + userDn);

			// Set password is a ldap modfy operation
			// and we'll update the userAccountControl
			// enabling the account and forcing the password to never expire
			if (password != null) {
				ModificationItem[] mods = new ModificationItem[2];

				//Replace the "unicdodePwd" attribute with a new value
				//Password must be both Unicode and a quoted string
				String newQuotedPassword = "\"" + password + "\"";
				byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");

				mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));
				mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl", Integer.toString(UF_NORMAL_ACCOUNT + UF_DONT_EXPIRE_PASSWD)));

				// Perform the update
				ctx.modifyAttributes(userDn, mods);
				log.info("Successfully set password and updated userAccountControl");
			}

			ctx.close();

		} catch (NamingException e) {
			log.info("NamingException while creating AD user " + screenName);
			throw new RuntimeException(e);
		} catch (IOException e) {
			log.info("IOException while creating AD user " + screenName);
			throw new RuntimeException(e);
		}
	}

Integrating Liferay 6 with Active Directory through LDAP

A common requirement for enterprises is to have the ability for the users in their Active Directory to be able to login into Liferay Portal(s) with Active Directory credentials. This can be achieved in Liferay by using the Liferay LDAP tool that comes bundled together with Liferay Community Edition. This tool works well when you just want to allow AD users to login with AD credentials into Liferay. There are a number issues with exporting user from Liferay to AD but lets just focus on import for now.

Liferary integrates with AD through importing the users. This means that if user wants to be able to login into the portal his record has to be present in the Liferay User database. So whenever you enter your credentials into the login screen of a Lifray Portal integrated with AD, the LDAP tool would always check your credentials entered againsts the AD and if there is a match you will be logged in. Lets have a look at the configurations required to enable this.

  1. Login into Liferay as an admin user.
  2. Go to Control Panel -> Portal Settings -> Authentication -> LDAP.
  3. Click Add, this will open ‘ADD LDAP Server’ page.
  4. Under Server Name – <an appropriate name for the configuration>
  5. Base Provider URL: <the URL of the LDAP Server>
    1. Use port 636 if the AD allows secure LDAP connections
    2. Otherwise, port 389 for insecure LDAP connections.
  6. Base DN: <enter the distinguished name of the Base OU where Liferay LDAP would search for users>
  7. Principal: <the username of the user you’d use to connect with AD>
  8. Credentials: <password>
  9. If you click ‘Test LDAP Connection’ now, you should see a pop up suggesting that Liferay has successfully connected to the LDAP server. If the message suggests failure to connect, then please make sure your configurations are correct before moving forward.
  10. Authentication Search filter: This is the filter that Liferay LDAP would use to search for a user in AD. So if you set it to (mail=@email_address@) then liferay would search would search for the user with the supplied email address in AD. You can set multiple filters on this, for example (&(objectCategory=user)(mail=@email_address@)) would also check that the objectCategory is user in addition to matching the email address.
  11. Import Search filter: This filter is used by Liferay LDAP tool for mass import of users. I would recommend to not use mass import if you dont have to and let import only happen at user login. For example, if you set this filter to (objectCategory=user), the LDAP tool will import all users that have objectCategory of user.
  12. Screen Name: cn (Screen Name is usually mapped to the cn attribute in AD, you could map it to sAMAccountName as well depending upon your requirements).
  13. Password: userPassword
  14. Email Address: mail
  15. First Name: givenName
  16. Last Name: sn
  17. Job Title: title
  18. If you click ‘Test LDAP Users’ you should see a list of users in a pop up. If you dont see a pop up or there are no users in the pop up, this means that the configurations you entered are not correct. Please go back and check your configurations.
  19. Please make sure that the export section is blank as we are not exporting users from Liferay to AD.
  20. Press Save.

All your configurations should now be saved in PortalPreferences tables in Liferay database.

Go back to the LDAP tab now and make sure you have checked Enabled and Required checkboxes and save your changes.

If you log out and log in with a user that exists in AD you should be able to login if you’ve enterd the correct credentials.

Integrating Liferay Developer Studio with JBoss Application Server 7.1

Liferay Developer Studio comes bundled with Tomcat server. Tomcat is usually useful to get things up and running however not so suitable for resource intensive applications. JBoss is usually is good choice for most requirements. The following are the instructions on how to integrate JBoss with Liferay.

  1. Download Liferay JBoss bundle from the liferay website and save it on your local drive. I saved liferay-portal-jboss-6.2-ee-sp7-20140807114015311.zip to my local drive.
  2. Unzip this file to a folder of your choice. I unzipped it to C:\work\liferay-portal\liferay-portal-6.2-ee-sp7. This will your JBOSS_BUNDLE_HOME.
  3. Start the JBoss Server.
  4. If you navigate to http://localhost:8080/, you will see a message indicating that you dont have the Liferay License.
  5. Refer to section in my previous blog post on updating license.
  6. You also need to connect to the same database that you set up with Liferay Developer Studio. To connect to the existing database:
    1. Create a new file called portal-ext.properties in JBOSS_BUNDLE_HOME.
    2. Add the following properties to the file and restart your JBoss Application Server.
jdbc.default.driverClassName=net.sourceforge.jtds.jdbc.Driver
jdbc.default.url=jdbc:jtds:sqlserver://localhost:1433/service_portal
jdbc.default.username=xxxxxx
jdbc.default.password=xxxxxx
  1. Create a new file called portal-setup-wizard.properties in JBOSS_BUNDLE_HOME, add the following lines and save it.
    1. admin.email.from.address={your admin user email address}
    2. admin.email.from.name=Admin User
    3. liferay.home=C:/work/liferay-portal/liferay-portal-6.2-ee-sp7
    4. setup.wizard.enabled=false
  2. Create a new file called build.(your username}.properties in {LIFERAY_HOME}\liferay-developer-studio\liferay-plugins-sdk-6.2 and add the following lines and save it.
app.server.type = jboss
app.server.jboss.dir = ${app.server.parent.dir}/jboss-7.1.1
app.server.jboss.lib.global.dir = ${app.server.jboss.dir}/modules/com/liferay/portal/main
app.server.jboss.portal.dir = ${app.server.jboss.dir}/standalone/deployments/ROOT.war
app.server.jboss.deploy.dir = ${app.server.jboss.dir}/standalone/deployments
app.server.parent.dir = C:/work/liferay-portal/liferay-portal-6.2-ee-sp7
  1. Restart your application server. You should automatically be navigated to the Portal Login page.