Tuesday, February 17, 2009

SSL (HTTPS) for Oracle Apex on Oracle 10g Express (XE)

Adding HTTPS to Oracle Application Express on Oracle 10g Express

CentOS 5.x
Oracle 10g Express
APEX 3.x upgrade
Apache 2.x
mod_ssl
open_ssl

If you are running APEX on Oracle 10g Express, you do not have access to the Wallet Manager per the OTN agreement.

You can still add HTTPS functionality, however, via Apache using mod_ssl.

While pervasive, mod_ssl is a third party module not supplied by Apache. If not already installed, yum install mod_ssl.

Let's start with a non-HTTPS example.

Within our Apache httpd.conf file, we create a reverse proxy to our Oracle APEX application.

There are any number of reasons for doing this:

1. We might do this for domain mapping (i.e. so www.yourdomain.com resolves to a specified application ID and landing page www.yourdomain.com/apex/f?p=101:1)

2. To allow access when behind a firewall where :8080 would block access

3. To increase security by running our Apache installation on a public facing server and back-ending to our Oracle server behind a firewall through which only our Apache server has access.

To create the reverse proxy we can use the following Virtual Host configuration under /etc/httpd/conf/httpd.conf

For simplicity, in the example below, Apache is installed on the same server as Oracle. If your installation is otherwise, simply substitute your server hostname or IP for localhost below.

<VirtualHost *:80>
ServerAdmin admin@yourdomain.com
DocumentRoot /home/yourdomain.com/htdocs
ServerName yourdomain.com
ServerAlias www.yourdomain.com
ErrorLog logs/yourdomain.com-error_log
CustomLog logs/yourdomain.com-access_log common
RewriteEngine On

RewriteRule ^/$ apex/f?p=101:1 [R=301]

ProxyRequests Off
<Proxy *>
Order allow,deny
Allow from all
</Proxy>
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>


Now, if we want to add HTTPS functionality, we begin by creating our SSL Key, CSR, and Certificate as we would for any standard SSL certificate.


If you have never done this before, RapidSSL has a very simple and useful step-by-step guides to doing so on Apache with OpenSSL and ModSSL:
 
1. Create Key and CSR: http://www.rapidssl.com/ssl-certificate-support/generate-csr/apache_mod_ssl.htm
 
2. Install Certificate: http://www.rapidssl.com/ssl-certificate-support/install-ssl-certificate/apache_mod_ssl.htm


If you want to take a practice run, or don't care about the certificate throwing a browser error, you can simply create a self-signed certificate.


I'm going to store my key and crt (certificate) files in the default locations.

With our certificate installed, lets return to the VHOST we created Now, under /etc/httpd/conf/httpd.conf change the Virtual Host we created above to below.


<VirtualHost *:80>
ServerAdmin admin@yourdomain.com
DocumentRoot /home/yourdomain.com/htdocs
ServerName yourdomain.com
ServerAlias www.yourdomain.com
ErrorLog logs/yourdomain.com-error_log
CustomLog logs/yourdomain.com-access_log common

RewriteEngine on

RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [L,R]

</VirtualHost>


The above rewrite RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [L,R] forces all requests made to :80 HTTP to :443 HTTPS (or whatever port you have configured to handle HTTPS requests).


Now that we have set up VHOST in httpd.conf and created our SSL key and certificate, we know need to create an additional VHOST under  /etc/httpd/conf.d/ssl.conf. The ssl.conf was created when we installed mod_ssl.

Under /etc/httpd/conf.d/ssl.conf configure the Virtual Host as below. I will be creating more than one SSL domain, so I am using IP 123.456.78.90 for this domain and will specify this in the Virtual Host below.


The SSL Virtual Host in our below in our /etc/httpd/conf.d/ssl.conf  file is truncated and I have highlighted the main areas where we have done our configuration in bold. I have also added a few comments in blue.

<VirtualHost 123.456.78.90:443>
# General setup for the virtual host, inherited from global configuration
DocumentRoot "/home/yourdomain.com/htdocs"
ServerName www.yourdomain.com:443


# Note that we have moved the reverse proxy from our httpd.conf file to our ssl.conf file
RewriteEngine on
RewriteRule ^/$ apex/f?p=101:1 [R=301]

ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/




# Use separate log files for the SSL virtual host; note that LogLevel
# is not inherited from httpd.conf.
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn

# SSL Engine Switch:
# Enable/Disable SSL for this virtual host.
SSLEngine on

# SSL Protocol support:
# List the enable protocol levels with which clients will be able to
# connect. Disable SSLv2 access by default:
SSLProtocol all -SSLv2

# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
# See the mod_ssl documentation for a complete list.
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW

# Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate. If
# the certificate is encrypted, then you will be prompted for a
# pass phrase. Note that a kill -HUP will prompt again. A new
# certificate can be generated using the genkey(1) command.
# The path below gives the location where we stored the SSL certificate we created
SSLCertificateFile /etc/httpd/conf/ssl.cert/www.youdomain.com.crt

# Server Private Key:
# If the key is not combined with the certificate, use this
# directive to point at the key file. Keep in mind that if
# you've both a RSA and a DSA private key you can configure
# both in parallel (to also allow the use of DSA ciphers, etc.)
# The path below gives the location of the key we created.
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/www.youdomain.com.key


SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0

CustomLog logs/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>


For Oracle APEX on Windows - I have never used a local Apache installation on W2K3. The simplest method for doing the above would be to use Linux server as front end with the proxy back-ended to the APEX installation on the Windows server. In Windows Firewall, you can then open access to your Linux box.

Footnote - for those new to Apache, the above does not touch on tuning. ReverseProxy and rewrites require tuning in order to perform well. Be sure to set KeepAlive to On, use mod_deflate (or gzip for 1.3), as well as set reasonable prefork MPM and worker MPM values. Apache tuning is beyond the scope of this post, but start with checking the docs and Googling these items to get you going.

Oracle APEX Hosting

Tuesday, February 3, 2009

Service Temporarily Unavailable 503 Code for APEX Apache Proxy

On running a standard proxypass for an apex application on new server, kept getting:
Service Temporarily Unavailable 503


vhost.....


<VirtualHost:*80>
ServerName domain.com
ServerAlias www.domain.com
DocumentRoot /var/www/html/domain.com/htdocs
ServerAdmin admin@domain.com

RewriteEngine On

RewriteRule ^/$ apex/f?p=113:1 [R=301]

ProxyRequests Off
<proxy>
Order deny,allow
Allow from all
</proxy>
ProxyPass / http://server:8080/
ProxyPassReverse / http://server:8080/
</VirtualHost>

Checking the error logs: /var/log/httpd/error_log I find:

[Sun Feb 01 21:01:42 2009] [error] (13)Permission denied: proxy: HTTP: attempt to connect to localhost:8080 (1.2.3.4) failed

In this case it was SELinux, giving me the option of either disbaling:

# vi /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - SELinux is fully disabled.
SELINUX=disabled
# SELINUXTYPE= type of policy in use. Possible values are:
# targeted - Only targeted network daemons are protected.
# strict - Full SELinux protection.
SELINUXTYPE=targeted

# SETLOCALDEFS= Check local definition changes
SETLOCALDEFS=0


Or, a more targeted:

/usr/sbin/setsebool httpd_can_network_connect 1


While in this case "(13)Permission denied:" was self-explanatory, the most common proxy failures I have come across were, in fact, due to my database not being configured on os properly.

Another area to check when your proxy stops proxying is the hostname configuration. Check /etc/hosts, /etc/hostname and make sure your hostname is set properly.

If it is, check listener.ora and tnsnames.ora under /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/network/admin and make sure they match what is in your host/hostname files.