Wednesday, December 17, 2008

Java XML validation, "Cannot find the declaration of element"?

Many thanks to Santiago Pericas-Geertsen, who blogged about this exact problem earlier this year. If you can't figure out for the life of you why your document won't validate, even though you know it's valid, try setting setNamespaceAware(true) on your DocumentBuilderFactory:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);

Chances are that's all you need and you'll be up and running.

Programming is easy, it's all the gotchas that make it hard.

Friday, August 1, 2008

Netbeans-Apache Commons library importer

2012 Update: You should be using Maven or Ivy these days. I don't even have copies of the original script anymore, sorry!

I threw together a script to download the latest version of all the Apache Commons components, and create the library files used for Netbeans. It's a little rough and short on docs, but easy enough to use. Some components can't be downloaded and processed easily (those with -e) and the signature of betwixt can't be verified because it's key is out of date, so we force it's acceptance (-f)

cd ~
mkdir JavaLibraries
wget http://www.apache.org/dist/commons/KEYS -qO - | gpg --import
./asfcommons2nb.pl --sig --dir JavaLibraries/Commons \
-e daemon \
-e httpclient \
-e jci \
-e latka \
-e attributes \
-f betwixt


When you're done, you'll want to copy the xml files from JavaLibraries/Commons/Libraries/
to ~/.netbeans/6.1/config/org-netbeans-api-project-libraries/Libraries/
Replace the bold part with the appropriate version.

It's pretty smart. It'll check to see that you have the current version and only update if you don't.

I like Netbeans' library feature, but keeping up to date on things sucks. If you don't care about docs, Ivy would suffice, but I do want instant javadoc access. That's why I'm using an IDE!

Anywho, it's public domain, feel free to send me enhancements or bugfixes.

Wednesday, March 19, 2008

CA signed SSL certs in glassfish, for lazy admins

So setting up CA signed SSL in Glassfish sucked, until I finally found the process for doing so. John Yeary outlines the process, but it's still manual and annoying.

Never do more than twice anything you can script, and so here we go. The script below is designed to work with CACert.org certificates. Save it to your local system and run it as a user who has access to write to the Glassfish installation.

#!/bin/sh
# Copyright 2008 Jeff Rodriguez [jeffrodriguez.com]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

/bin/echo "This script was designed to work with CACert.org."
/bin/echo "It may work with other sites, YMMV."
/bin/echo "USE AT YOUR OWN RISK."
/bin/echo -e "\n\n"

read -rp "SSL domain name [`hostname`]: " DOMAIN
if [ -z "$DOMAIN" ]; then DOMAIN="`hostname`"; fi

read -rp "AppServer domain directory [/home/`whoami`/SUNWappserver/domains/domain1]: " DIR
if [ -z "$DIR" ]; then DIR="/home/`whoami`/SUNWappserver/domains/domain1"; fi

read -rp "Keystore password [changeit]: " KSPASS
if [ -z "$KSPASS" ]; then KSPASS="changeit"; fi

# Make sure the domain directory is correct
KS="$DIR/config/keystore.jks"
if [ ! -e "$KS" -a ! -w "$KS" ]; then
/bin/echo "Your keystore ($KS) is not writable."
exit 1
fi

# Handy alias
KSCMD="keytool -keystore $KS -storepass $KSPASS"

# Generate the key
if ( ! $KSCMD -genkey -keyalg RSA -alias $DOMAIN -keypass $KSPASS -noprompt -validity 365 -dname "cn=$DOMAIN"); then
/bin/echo "Failed to generate key."
exit 1
fi
/bin/echo -e "\n\nA private key has been created in your app server's keystore."
/bin/echo "If this script fails at any point, and you wish to start over, you must delete this private key with the command: "
/bin/echo "$KSCMD -delete -alias $DOMAIN"
read -sp "Press enter to continue." REPLY
/bin/echo -e "\n\n"

# Create the CSR
if ( ! $KSCMD -certreq -v -alias $DOMAIN -file /tmp/$DOMAIN.csr); then
/bin/echo "Failed to create certificate signing request."
exit 1
fi

/bin/echo "Below is your Certificate Signing Request (CSR)."
/bin/echo "On the CACert.org website, go to Server Certificates -> New. Paste the text below into the form and submit it."
cat /tmp/$DOMAIN.csr
rm -f /tmp/$DOMAIN.csr

# Get the certificate
/bin/echo -e "\n\nCACert will generate a signed certificate. Paste it here, finish with EOF (CTRL+D)."
cat > /tmp/$DOMAIN.crt

# Fetch the CACert certificates
/bin/echo "Before you can use your certificate, it has to be imported to the app server keystore. To do that, we first have to import the CACert.org certificates."
read -rp "Would you like the script to automatically download the certificates? [y|N]: " DLCERTS

if [ $DLCERTS = 'Y' -o $DLCERTS = 'y' ]; then
wget -q --no-check-certificate -O /tmp/cacert_root.crt "http://www.cacert.org/certs/root.crt"
wget -q --no-check-certificate -O /tmp/cacert_class3.crt "http://www.cacert.org/certs/class3.crt"
else
/bin/echo "You have chosen not to automatically download the certificates. To do this manually,"
/bin/echo "Go to http://www.cacert.org/index.php?id=3"
/bin/echo "Save the Class 1 PKI Key Root Certificate (PEM Format) as /tmp/cacert_root.crt"
/bin/echo "Save the Class 3 PKI Key Root Certificate (PEM Format) as /tmp/cacert_class3.crt"
read -sp "Press enter to continue." REPLY
fi

if [ ! -e /tmp/cacert_root.crt -o ! -e /tmp/cacert_class3.crt ]; then
/bin/echo "CACert certificates weren't found in /tmp. Either automatic download failed or you have not manually downloaded the certificates properly."
exit 1
fi

# Import the certificates
if ( ! $KSCMD -import -v -alias cacert -trustcacerts -noprompt -file /tmp/cacert_root.crt); then
/bin/echo "Failed to import CACert root certificate."
exit 1
fi
if ( ! $KSCMD -import -v -alias cacert3 -trustcacerts -noprompt -file /tmp/cacert_class3.crt); then
/bin/echo "Failed to import CACert class 3 certificate."
exit 1
fi
if ( ! $KSCMD -import -v -alias $DOMAIN -trustcacerts -noprompt -file /tmp/$DOMAIN.crt); then
/bin/echo "Failed to import domain certificate."
exit 1
fi

# Cleanup
rm -f /tmp/cacert_root.crt
rm -f /tmp/cacert_class3.crt
rm -f /tmp/$DOMAIN.crt
$KSCMD -delete -alias cacert
$KSCMD -delete -alias cacert3

# Final instructions for the user
/bin/echo -e "\n\n"
/bin/echo "The certificate has been imported into your app server keystore."
/bin/echo "To use the certificate follow these last steps:"
/bin/echo " 1. Go to your Admin Console (http://$DOMAIN:4848), Configuration, HTTP Service, HTTP Listeners, http-listener-2 (or whatever your SSL listener is)."
/bin/echo " 2. On the SSL tab, set your Certificate Nickname to $DOMAIN, and click save."
/bin/echo " 3. Restart the app server."
/bin/echo "NOTE: Your certificate will expire in 1 year, you must update the certificate before then or browsers will receive SSL warnings; other programs may fail entirely."
/bin/echo "Mark your calendar. No, really."
/bin/echo -e "\n\n"
/bin/echo "If something went, or goes wrong, it could prevent your app server from starting. One possible remedy is to locate your SSL http listener in $DIR/config/domain.xml and disable it."

Though supposedly, it's technically possible to use an existing private key and certificate, you'll shoot yourself in the face before you finish. Cut your losses and just start over with a new private key and cert. You'll have to pardon me if the script is a bit rough around the edges. Send patches my way if you like.