Implemented securing Authentication and Session Tokens using
WS-Security.
This commit is contained in:
parent
2ec99203a2
commit
b06912c332
@ -265,6 +265,7 @@ package/linux/Makefile
|
||||
package/linux/CASA_auth_token_svc.spec
|
||||
server/Makefile
|
||||
server/Svc/Makefile
|
||||
server/Svc/external/Makefile
|
||||
server/Svc/src/Makefile
|
||||
server/Svc/src/com/Makefile
|
||||
server/Svc/src/com/novell/Makefile
|
||||
|
@ -20,7 +20,7 @@
|
||||
#######################################################################
|
||||
|
||||
SUBDIRS = src
|
||||
DIST_SUBDIRS = src
|
||||
DIST_SUBDIRS = src external
|
||||
|
||||
EXTRA_DIST = authtoken.settings \
|
||||
identoken.settings \
|
||||
@ -34,6 +34,7 @@ ROOT = ../..
|
||||
LIBDIR = $(ROOT)/$(LIB)
|
||||
|
||||
IDENT_ABSTRACTION_DIR = /usr/share/java/identity-abstraction
|
||||
AXIS_JARS_DIR = external
|
||||
|
||||
JAVAROOT = .
|
||||
JAVAC= javac
|
||||
@ -50,6 +51,8 @@ JAVAFILES = src/com/novell/casa/authtoksvc/ProtoDefs.java \
|
||||
src/com/novell/casa/authtoksvc/AuthTokenConfig.java \
|
||||
src/com/novell/casa/authtoksvc/EnabledSvcsConfig.java \
|
||||
src/com/novell/casa/authtoksvc/AuthMechanism.java \
|
||||
src/com/novell/casa/authtoksvc/WSSecurity.java \
|
||||
src/com/novell/casa/authtoksvc/SessionToken.java \
|
||||
src/com/novell/casa/authtoksvc/Authenticate.java \
|
||||
src/com/novell/casa/authtoksvc/RpcMethod.java \
|
||||
src/com/novell/casa/authtoksvc/Rpc.java \
|
||||
@ -66,8 +69,7 @@ JAVAFILES = src/com/novell/casa/authtoksvc/ProtoDefs.java \
|
||||
src/com/novell/casa/authtoksvc/GetAuthTokReqMsg.java \
|
||||
src/com/novell/casa/authtoksvc/GetAuthTokRespMsg.java \
|
||||
src/com/novell/casa/authtoksvc/Krb5Authenticate.java \
|
||||
src/com/novell/casa/authtoksvc/PwdAuthenticate.java \
|
||||
src/com/novell/casa/authtoksvc/SessionToken.java
|
||||
src/com/novell/casa/authtoksvc/PwdAuthenticate.java
|
||||
|
||||
BUILDDIR = build
|
||||
|
||||
@ -77,8 +79,12 @@ AUTHTOKEN_FILES = -C $(BUILDDIR)/webapp/WEB-INF/classes com
|
||||
|
||||
CLASSES = $(addprefix $(BUILDDIR)/, $(JAVAFILES:%.java=%.class))
|
||||
|
||||
#AXIS_LIBS = $(AXIS_JARS_DIR)/axis.jar:$(AXIS_JARS_DIR)/axis-ant.jar:$(AXIS_JARS_DIR)/commons-discovery-0.2.jar:$(AXIS_JARS_DIR)/commons-logging-1.0.4.jar:$(AXIS_JARS_DIR)/commons-logging-api.jar:$(AXIS_JARS_DIR)/jaxrpc.jar:$(AXIS_JARS_DIR)/log4j-1.2.8.jar:$(AXIS_JARS_DIR)/saaj.jar:$(AXIS_JARS_DIR)/wsdl4j-1.5.1.jar:$(AXIS_JARS_DIR)/wss4j-1.5.0.jar:$(AXIS_JARS_DIR)/xalan.jar:$(AXIS_JARS_DIR)/xercesImpl.jar:$(AXIS_JARS_DIR)/xml-apis.jar:$(AXIS_JARS_DIR)/xmlsec-1.2.1.jar
|
||||
AXIS_LIBS = $(AXIS_JARS_DIR)/axis.jar:$(AXIS_JARS_DIR)/saaj.jar:$(AXIS_JARS_DIR)/wss4j-1.5.0.jar:$(AXIS_JARS_DIR)/xmlsec-1.2.1.jar
|
||||
#AXIS_LIBS = $(AXIS_JARS_DIR)/wss4j-1.5.0.jar
|
||||
|
||||
LIBS = /usr/share/java/servletapi5.jar
|
||||
CLASSPATH = $(IDENT_ABSTRACTION_DIR)/identity-abstraction.jar:$(LIBS)
|
||||
CLASSPATH = $(AXIS_LIBS):$(IDENT_ABSTRACTION_DIR)/identity-abstraction.jar:$(LIBS)
|
||||
|
||||
CUR_DIR := $(shell pwd)
|
||||
|
||||
@ -98,6 +104,7 @@ $(BUILDDIR)/$(WEBAPP): $(BUILDDIR) $(CLASSES)
|
||||
cp src/com/novell/casa/authtoksvc/Pwd_mechanism.settings $(BUILDDIR)/webapp/WEB-INF/conf/installed_auth_mechanisms/PwdAuthenticate/mechanism.settings
|
||||
cp $(IDENT_ABSTRACTION_DIR)/*.jar $(BUILDDIR)/webapp/WEB-INF/lib/
|
||||
rm $(BUILDDIR)/webapp/WEB-INF/lib/identity-abstraction.jar
|
||||
cp $(AXIS_JARS_DIR)/*.jar $(BUILDDIR)/webapp/WEB-INF/lib/
|
||||
ls $(BUILDDIR)/webapp/WEB-INF/lib/
|
||||
jar cvf $(BUILDDIR)/$(WEBAPP) -C $(BUILDDIR)/webapp .
|
||||
cp $(BUILDDIR)/$(WEBAPP) $(LIBDIR)/java/
|
||||
|
@ -69,6 +69,8 @@ Thhe following is an example svc.settings file:
|
||||
<IAConfigFile>/home/jluciani/jakarta-tomcat-5.0.28/webapps/CasaAuthTokenSvc/WEB-INF/conf/iaRealms.xml</IAConfigFile>
|
||||
<ReconfigureInterval>60</ReconfigureInterval>
|
||||
<startSearchContext>o=novell</startSearchContext>
|
||||
<KeyStoreUser>privKey<KeyStoreUser>
|
||||
<KeyStorePwd>foobar<KeyStorePwd>
|
||||
</settings>
|
||||
|
||||
Note the following about the sample svc.settings file:
|
||||
@ -102,6 +104,12 @@ Note the following about the sample svc.settings file:
|
||||
from the root of the tree. This setting or an equivalent setting will be moved
|
||||
to the identity abstraction configuration file where it belongs. Once this is done,
|
||||
the setting will no longer be recognized within the svc.settings file.
|
||||
|
||||
- The KeyStoreUses setting specifies the user's alias name in the keystore that identifies
|
||||
the private key that is to be used to sign tokens.
|
||||
|
||||
- The KeyStorePwd setting specifies the password of the user specified by KeyStoreUser to get
|
||||
the private signing key from the keystore.
|
||||
|
||||
CONFIGURING SERVICES TO CONSUME CASA AUTHENTICATION TOKENS
|
||||
|
||||
|
52
CASA-auth-token/java/server/Svc/external/Makefile.am
vendored
Normal file
52
CASA-auth-token/java/server/Svc/external/Makefile.am
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
#######################################################################
|
||||
#
|
||||
# Copyright (C) 2006 Novell, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free
|
||||
# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#
|
||||
# Author: Juan Carlos Luciani <jluciani@novell.com>
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
SUBDIRS =
|
||||
|
||||
DIST_SUBDIRS =
|
||||
|
||||
CFILES =
|
||||
|
||||
EXTRA_DIST = axis.jar \
|
||||
axis-ant.jar \
|
||||
commons-discovery-0.2.jar \
|
||||
commons-logging-1.0.4.jar \
|
||||
commons-logging-api.jar \
|
||||
jaxrpc.jar \
|
||||
log4j.properties \
|
||||
log4j-1.2.8.jar \
|
||||
README \
|
||||
saaj.jar \
|
||||
wsdl4j-1.5.1.jar \
|
||||
wss4j-1.5.0.jar \
|
||||
xalan.jar \
|
||||
xercesImpl.jar \
|
||||
xml-apis.jar \
|
||||
xmlsec-1.2.1.jar
|
||||
|
||||
.PHONY: package package-clean package-install package-uninstall
|
||||
package package-clean package-install package-uninstall:
|
||||
$(MAKE) -C $(TARGET_OS) $@
|
||||
|
||||
maintainer-clean-local:
|
||||
rm -f Makefile.in
|
||||
|
25
CASA-auth-token/java/server/Svc/external/README
vendored
Normal file
25
CASA-auth-token/java/server/Svc/external/README
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
The following describes the source of the files present in this folder.
|
||||
|
||||
axis-1_4 ----> axis-ant.jar
|
||||
axis-1_4 ----> axis.jar
|
||||
axis-1_4 ----> commons-discovery-0.2.jar
|
||||
axis-1_4 ----> commons-logging-1.0.4.jar
|
||||
xml-security-1_2_1 ----> commons-logging-api.jar
|
||||
axis-1_4 ----> jaxrpc.jar
|
||||
axis-1_4 ----> log4j-1.2.8.jar
|
||||
axis-1_4 ----> log4j.properties
|
||||
axis-1_4 ----> saaj.jar
|
||||
axis-1_4 ----> wsdl4j-1.5.1.jar
|
||||
wss4j-1.5 ----> wss4j-1.5.0.jar
|
||||
xml-security-1_2_1 ----> xalan.jar
|
||||
xml-security-1_2_1 ----> xercesImpl.jar
|
||||
xml-security-1_2_1 ----> xml-apis.jar
|
||||
xml-security-1_2_1 ----> xmlsec-1.2.1.jar
|
||||
|
||||
xml-security-1_2_1 - URL: http://xml.apache.org/security/dist/java-library/ - File: xml-security-bin-1_2_1.zip
|
||||
|
||||
axis-1_4 - URL: http://www.apache.org/dyn/closer.cgi/ws/axis/1_4 - File: axis-bin-1_4.tar.gz
|
||||
|
||||
wss4j-1.5 - URL: http://www.apache.org/dyn/dyn/closer.cgi/ws/wss4j/ - File: wss4j-bin-1.5.0.zip
|
||||
|
||||
|
BIN
CASA-auth-token/java/server/Svc/external/axis-ant.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/axis-ant.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/axis.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/axis.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/commons-discovery-0.2.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/commons-discovery-0.2.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/commons-logging-1.0.4.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/commons-logging-1.0.4.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/commons-logging-api.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/commons-logging-api.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/jaxrpc.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/jaxrpc.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/log4j-1.2.8.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/log4j-1.2.8.jar
vendored
Normal file
Binary file not shown.
20
CASA-auth-token/java/server/Svc/external/log4j.properties
vendored
Normal file
20
CASA-auth-token/java/server/Svc/external/log4j.properties
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Set root category priority to INFO and its only appender to CONSOLE.
|
||||
log4j.rootCategory=INFO, CONSOLE
|
||||
#log4j.rootCategory=INFO, CONSOLE, LOGFILE
|
||||
|
||||
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
|
||||
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
|
||||
|
||||
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
|
||||
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.CONSOLE.Threshold=INFO
|
||||
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n
|
||||
|
||||
# LOGFILE is set to be a File appender using a PatternLayout.
|
||||
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
|
||||
log4j.appender.LOGFILE.File=axis.log
|
||||
log4j.appender.LOGFILE.Append=true
|
||||
log4j.appender.LOGFILE.Threshold=INFO
|
||||
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.LOGFILE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
|
BIN
CASA-auth-token/java/server/Svc/external/saaj.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/saaj.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/wsdl4j-1.5.1.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/wsdl4j-1.5.1.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/wss4j-1.5.0.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/wss4j-1.5.0.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/xalan.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/xalan.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/xercesImpl.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/xercesImpl.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/xml-apis.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/xml-apis.jar
vendored
Normal file
Binary file not shown.
BIN
CASA-auth-token/java/server/Svc/external/xmlsec-1.2.1.jar
vendored
Normal file
BIN
CASA-auth-token/java/server/Svc/external/xmlsec-1.2.1.jar
vendored
Normal file
Binary file not shown.
@ -256,6 +256,11 @@ public class AuthReqMsg
|
||||
m_state = AWAITING_REALM_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_REALM_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_authReqMsg.m_realm = m_authReqMsg.m_realm.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
case AWAITING_MECH_DATA:
|
||||
// Consume the data
|
||||
m_authReqMsg.m_authMechanism = new String(ch, start, length);
|
||||
@ -264,6 +269,11 @@ public class AuthReqMsg
|
||||
m_state = AWAITING_MECH_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_MECH_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_authReqMsg.m_authMechanism = m_authReqMsg.m_authMechanism.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
case AWAITING_AUTH_MECH_TOKEN_DATA:
|
||||
// Consume the data
|
||||
m_authReqMsg.m_authMechToken = new String(ch, start, length);
|
||||
@ -272,6 +282,11 @@ public class AuthReqMsg
|
||||
m_state = AWAITING_AUTH_MECH_TOKEN_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_AUTH_MECH_TOKEN_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_authReqMsg.m_authMechToken = m_authReqMsg.m_authMechToken.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
|
@ -26,20 +26,26 @@ package com.novell.casa.authtoksvc;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
import org.apache.axis.Message;
|
||||
import org.apache.axis.MessageContext;
|
||||
import org.apache.axis.client.AxisClient;
|
||||
import org.apache.axis.configuration.NullProvider;
|
||||
import org.apache.axis.message.SOAPEnvelope;
|
||||
import org.apache.axis.message.SOAPBody;
|
||||
import org.apache.axis.message.MessageElement;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/*
|
||||
* AuthToken Class.
|
||||
*
|
||||
* This class constructs authentication tokens that clients can present
|
||||
* to services for authentication. The format of the authentication token
|
||||
* is as follows:
|
||||
*
|
||||
* <?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
* to services for authentication. The authentication token consists of
|
||||
* a SOAP message secured with WSSecurity with the appropriate elements signed
|
||||
* and with a timestamp. The body of the SOAP message is as follows:
|
||||
*
|
||||
* <auth_token>
|
||||
* <signature>signature value</signature>
|
||||
* <lifetime>lifetime value</lifetime>
|
||||
@ -51,280 +57,23 @@ public class AuthToken
|
||||
{
|
||||
|
||||
private String m_token;
|
||||
private String m_lifetime;
|
||||
private String m_lifetimeShorter;
|
||||
private String m_identityTokenType;
|
||||
private StringBuffer m_identityToken;
|
||||
private String m_signature;
|
||||
private String m_lifetime = "";
|
||||
private String m_lifetimeShorter = "";
|
||||
private String m_identityTokenType = null;
|
||||
private String m_identityToken = null;
|
||||
|
||||
/*
|
||||
* Class for handling parsing events.
|
||||
*/
|
||||
private class SAXHandler extends org.xml.sax.helpers.DefaultHandler
|
||||
{
|
||||
private final static int AWAITING_ROOT_ELEMENT_START = 0;
|
||||
private final static int AWAITING_ROOT_ELEMENT_END = 1;
|
||||
private final static int AWAITING_SIGNATURE_ELEMENT_START = 2;
|
||||
private final static int AWAITING_SIGNATURE_ELEMENT_END = 3;
|
||||
private final static int AWAITING_SIGNATURE_DATA = 4;
|
||||
private final static int AWAITING_LIFETIME_ELEMENT_START = 5;
|
||||
private final static int AWAITING_LIFETIME_ELEMENT_END = 6;
|
||||
private final static int AWAITING_LIFETIME_DATA = 7;
|
||||
private final static int AWAITING_IDENT_TOKEN_ELEMENT_START = 8;
|
||||
private final static int AWAITING_IDENT_TOKEN_ELEMENT_END = 9;
|
||||
private final static int AWAITING_IDENT_TOKEN_DATA = 10;
|
||||
private final static int AWAITING_TYPE_ELEMENT_START = 11;
|
||||
private final static int AWAITING_TYPE_ELEMENT_END = 12;
|
||||
private final static int AWAITING_TYPE_DATA = 13;
|
||||
private final static int DONE_PARSING = 14;
|
||||
static final String authTokenSoapMsg =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<SOAP-ENV:Envelope" +
|
||||
" xmlns:SOAP-ENV=\"http://www.w3.org/2003/05/soap-envelope\"\n" +
|
||||
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
|
||||
" <SOAP-ENV:Body>" +
|
||||
" <auth_token><ident_token><type></type></ident_token></auth_token>" +
|
||||
" </SOAP-ENV:Body>" +
|
||||
"</SOAP-ENV:Envelope>";
|
||||
|
||||
private AuthToken m_AuthToken;
|
||||
private int m_state;
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public SAXHandler (AuthToken AuthToken)
|
||||
{
|
||||
super();
|
||||
|
||||
// Initialize our members
|
||||
m_AuthToken = AuthToken;
|
||||
m_state = AWAITING_ROOT_ELEMENT_START;
|
||||
}
|
||||
|
||||
/*
|
||||
* endDocument() implementation.
|
||||
*/
|
||||
public void endDocument () throws SAXException
|
||||
{
|
||||
// Verify that we obtained all of the required elements
|
||||
if (m_state != DONE_PARSING)
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.endDocument()- Missing element");
|
||||
throw new SAXException("Missing element");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* startElement() implementation.
|
||||
*/
|
||||
public void startElement (String uri, String name, String qName, org.xml.sax.Attributes atts) throws SAXException
|
||||
{
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.authTokenElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_SIGNATURE_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_SIGNATURE_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.signatureElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_SIGNATURE_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_LIFETIME_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.lifetimeElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_LIFETIME_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AWAITING_IDENT_TOKEN_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.identTokenElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_TYPE_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_TYPE_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.typeElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_TYPE_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
System.err.println("AuthToken SAXHandler.startElement()- State error");
|
||||
throw new SAXException("State error");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* endElement() immplementation.
|
||||
*/
|
||||
public void endElement (String uri, String name, String qName) throws SAXException
|
||||
{
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.authTokenElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = DONE_PARSING;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_SIGNATURE_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.signatureElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_LIFETIME_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_LIFETIME_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.lifetimeElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_IDENT_TOKEN_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_TYPE_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.typeElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_IDENT_TOKEN_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_IDENT_TOKEN_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.identTokenElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_ROOT_ELEMENT_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("AuthToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
System.err.println("AuthToken SAXHandler.startElement()- State error");
|
||||
throw new SAXException("State error");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* character() implementation.
|
||||
*/
|
||||
public void characters (char ch[], int start, int length) throws SAXException
|
||||
{
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_SIGNATURE_DATA:
|
||||
// Consume the data
|
||||
m_AuthToken.m_signature = new String(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_SIGNATURE_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_LIFETIME_DATA:
|
||||
// Consume the data
|
||||
m_AuthToken.m_lifetime = new String(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_LIFETIME_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_TYPE_DATA:
|
||||
// Consume the data
|
||||
m_AuthToken.m_identityTokenType = new String(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_TYPE_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_IDENT_TOKEN_DATA:
|
||||
case AWAITING_IDENT_TOKEN_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_AuthToken.m_identityToken.append(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_IDENT_TOKEN_ELEMENT_END;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static final private MessageContext axisMsgContext = new MessageContext(new AxisClient(new NullProvider()));
|
||||
|
||||
/*
|
||||
* Constructor.
|
||||
@ -354,37 +103,28 @@ public class AuthToken
|
||||
targetHost,
|
||||
svcConfig);
|
||||
|
||||
m_identityToken = new StringBuffer();
|
||||
m_identityToken.append(identityToken.getEncodedToken());
|
||||
m_identityToken = identityToken.getEncodedToken();
|
||||
m_identityTokenType = identityToken.getProviderType();
|
||||
|
||||
m_lifetime = authTokenConfig.getSetting(AuthTokenConfig.TokenLifetime);
|
||||
m_lifetimeShorter = authTokenConfig.getSetting(AuthTokenConfig.LifetimeShorter);
|
||||
|
||||
// Generate a signature
|
||||
// tbd - Over identToken, identToken type, and lifetime data.
|
||||
m_signature = "tbd";
|
||||
// Create AuthTokenMessage
|
||||
Message authTokenMessage = getMessage(identityToken.getEncodedToken(),
|
||||
identityToken.getProviderType(),
|
||||
Integer.valueOf(m_lifetime).intValue(),
|
||||
svcConfig);
|
||||
|
||||
// Get a StringBuffer to help us with the construction of the token
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
// Start building the message
|
||||
sb.append(ProtoDefs.xmlDeclaration + "\r\n");
|
||||
sb.append("<" + ProtoDefs.authTokenElementName + ">" + "\r\n");
|
||||
sb.append("<" + ProtoDefs.signatureElementName + ">" + m_signature + "</" + ProtoDefs.signatureElementName + ">" + "\r\n");
|
||||
sb.append("<" + ProtoDefs.lifetimeElementName + ">" + m_lifetime + "</" + ProtoDefs.lifetimeElementName + ">" + "\r\n");
|
||||
sb.append("<" + ProtoDefs.identTokenElementName + ">"
|
||||
+ "<" + ProtoDefs.typeElementName + ">" + m_identityTokenType + "</" + ProtoDefs.typeElementName + ">"
|
||||
+ m_identityToken + "</" + ProtoDefs.identTokenElementName + ">" + "\r\n");
|
||||
sb.append("</" + ProtoDefs.authTokenElementName + ">" + "\r\n");
|
||||
|
||||
// Save the token
|
||||
m_token = sb.toString();
|
||||
// Now save the message as a string
|
||||
OutputStream outStream = new ByteArrayOutputStream();
|
||||
authTokenMessage.writeTo(outStream);
|
||||
m_token = outStream.toString();
|
||||
outStream.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// tbd
|
||||
System.err.println("AuthToken()- Exception: " + e.toString());
|
||||
System.err.println("AuthToken()- Exception: " + e.toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -402,33 +142,102 @@ public class AuthToken
|
||||
// Decode the token string
|
||||
m_token = Base64Coder.decode(token);
|
||||
|
||||
// Instantiate string buffer for the identity token
|
||||
m_identityToken = new StringBuffer();
|
||||
// Now instantiate a SOAP message with the string
|
||||
InputStream inStream = new ByteArrayInputStream(m_token.getBytes());
|
||||
Message message = new Message(inStream);
|
||||
|
||||
// Get access to the SOAP Envelope
|
||||
SOAPEnvelope envelope = message.getSOAPEnvelope();
|
||||
|
||||
// Verify the message
|
||||
if (WSSecurity.verifyMessage(envelope))
|
||||
{
|
||||
// Message verification succeded, now obtain the identity token
|
||||
// and its type from the message body.
|
||||
SOAPBody body = (SOAPBody) envelope.getBody();
|
||||
QName authTokenElementName = new QName("auth_token");
|
||||
MessageElement authTokenElement = body.getChildElement(authTokenElementName);
|
||||
QName identTokenElementName = new QName("ident_token");
|
||||
MessageElement identTokenElement = authTokenElement.getChildElement(identTokenElementName);
|
||||
if (identTokenElement != null)
|
||||
{
|
||||
QName identTokenTypeElementName = new QName("type");
|
||||
MessageElement identTokenTypeElement = identTokenElement.getChildElement(identTokenTypeElementName);
|
||||
if (identTokenTypeElement != null)
|
||||
{
|
||||
m_identityToken = identTokenElement.getChildNodes().item(1).getNodeValue();
|
||||
m_identityTokenType = identTokenTypeElement.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_identityToken == null || m_identityTokenType == null)
|
||||
{
|
||||
System.out.println("AuthToken()- Required data missing from authentication token");
|
||||
throw new Exception("Error: Required data missing from Authentication Token");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Message verification failed
|
||||
System.err.println("AuthToken()- Invalid Authentication Token");
|
||||
throw new Exception("Invalid Authentication Token");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get AuthToken SOAP Message
|
||||
*
|
||||
* @param identityToken String containing the identity token that should be part of the message
|
||||
* @param identityTokenType String containing the identity token type
|
||||
* @param lifetime Lifetime that should be specified in the message timestamp (seconds)
|
||||
* @param svcConfig Service configuratio object
|
||||
* @return <code>Message<code> AuthToken message, null if the method fails.
|
||||
*/
|
||||
private Message getMessage(String identityToken,
|
||||
String identityTokenType,
|
||||
int lifetime,
|
||||
SvcConfig svcConfig)
|
||||
{
|
||||
Message secureMessage;
|
||||
|
||||
// Now parse the token into its elements
|
||||
try
|
||||
{
|
||||
// Parse the AuthToken
|
||||
XMLReader xr = XMLReaderFactory.createXMLReader();
|
||||
SAXHandler handler = new SAXHandler(this);
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
// Build SOAP Message with an identity token in the body
|
||||
//
|
||||
// First create a message and obtain its body
|
||||
InputStream inStream = new ByteArrayInputStream(authTokenSoapMsg.getBytes());
|
||||
Message message = new Message(inStream);
|
||||
message.setMessageContext(axisMsgContext);
|
||||
SOAPBody body = (SOAPBody) message.getSOAPBody();
|
||||
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(m_token.getBytes());
|
||||
InputSource source = new InputSource(inStream);
|
||||
xr.parse(source);
|
||||
// Get access to the auth_token element
|
||||
QName authTokenElementName = new QName("auth_token");
|
||||
MessageElement authTokenElement = body.getChildElement(authTokenElementName);
|
||||
|
||||
// Verify the signature
|
||||
// tbd
|
||||
// Get access to the ident_token element and set its value
|
||||
QName identTokenElementName = new QName("ident_token");
|
||||
MessageElement identTokenElement = authTokenElement.getChildElement(identTokenElementName);
|
||||
identTokenElement.addTextNode(identityToken);
|
||||
|
||||
// Verify that the token has not expired
|
||||
// tbd
|
||||
// Get access to the identity token type element element and set its value
|
||||
QName identTokenTypeElementName = new QName("type");
|
||||
MessageElement identTokenTypeElement = identTokenElement.getChildElement(identTokenTypeElementName);
|
||||
identTokenTypeElement.setValue(identityTokenType);
|
||||
|
||||
// Now we need to secure the SOAP message that we created, we are doing to
|
||||
// do so by adding a timestamp and signing the timestamp as well as the body.
|
||||
// To do this we are going to leverage WS-Security.
|
||||
secureMessage = WSSecurity.secureSOAPEnvelope(message.getSOAPEnvelope(),
|
||||
lifetime,
|
||||
svcConfig);
|
||||
}
|
||||
catch (SAXException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
System.err.println("AuthToken()- Parse exception: " + e.toString());
|
||||
throw new Exception("Protocol error");
|
||||
System.out.println("AuthToken.getMessage() - Exception caught building message, error: " + e.getMessage());
|
||||
secureMessage = null;
|
||||
}
|
||||
|
||||
return secureMessage;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -441,11 +250,20 @@ public class AuthToken
|
||||
|
||||
/*
|
||||
* Returns the lifetime of the token.
|
||||
*
|
||||
* Note: It is only valid to execute this procedure if its called on an object
|
||||
* instantiated via the constructor which takes a lifetime parameter.
|
||||
*/
|
||||
public String getLifetime()
|
||||
public String getLifetime() throws Exception
|
||||
{
|
||||
// tbd - Convert to tokenLifetime and lifetimeShorter to ints, substractand then convert result to string
|
||||
return "60";
|
||||
// Throw exeption if the lifetime parameter is not set
|
||||
if (m_lifetime.length() == 0)
|
||||
{
|
||||
System.out.println("AuthToken.getLifetime() - Called when lifetime is not set");
|
||||
throw new Exception("Error: Called getLifetime while not set");
|
||||
}
|
||||
|
||||
return Integer.toString(Integer.valueOf(m_lifetime).intValue() - Integer.valueOf(m_lifetimeShorter).intValue());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -453,7 +271,7 @@ public class AuthToken
|
||||
*/
|
||||
public String getIdentityToken()
|
||||
{
|
||||
return m_identityToken.toString();
|
||||
return m_identityToken;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -281,16 +281,16 @@ public class Authenticate implements RpcMethod
|
||||
// An identity was resolved, get a SessionToken for it.
|
||||
SessionToken sessionToken = new SessionToken(identId,
|
||||
authReqMsg.getRealm(),
|
||||
m_svcConfig.getSetting(SvcConfig.SessionTokenLifetime));
|
||||
m_svcConfig.getSetting(SvcConfig.SessionTokenLifetime),
|
||||
m_svcConfig);
|
||||
|
||||
// Write out the response
|
||||
String respLifetime = Integer.toString(Integer.valueOf(m_svcConfig.getSetting(SvcConfig.SessionTokenLifetime)).intValue()
|
||||
- Integer.valueOf(m_svcConfig.getSetting(SvcConfig.LifetimeShorter)).intValue());
|
||||
AuthRespMsg authRespMsg = new AuthRespMsg(ProtoDefs.httpOkStatusMsg,
|
||||
ProtoDefs.httpOkStatusCode,
|
||||
sessionToken.toString(),
|
||||
m_svcConfig.getSetting(SvcConfig.SessionTokenLifetime));
|
||||
// tbd - Convert to ints, perform calculation, and then convert result to string
|
||||
//m_svcConfig.getSetting(SvcConfig.SessionTokenLifetime)
|
||||
//- m_svcConfig.getSetting(SvcConfig.LifetimeShorter));
|
||||
respLifetime);
|
||||
out.println(authRespMsg.toString());
|
||||
}
|
||||
else
|
||||
|
@ -102,7 +102,6 @@ public class GetAuthPolicyReqMsg
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.getAuthPolicyRequestElementName.equals(qName))
|
||||
@ -160,7 +159,6 @@ public class GetAuthPolicyReqMsg
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.getAuthPolicyRequestElementName.equals(qName))
|
||||
@ -217,7 +215,6 @@ public class GetAuthPolicyReqMsg
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_SERVICE_DATA:
|
||||
// Consume the data
|
||||
m_GetAuthPolicyReqMsg.m_serviceName = new String(ch, start, length);
|
||||
@ -226,6 +223,11 @@ public class GetAuthPolicyReqMsg
|
||||
m_state = AWAITING_SERVICE_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_SERVICE_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_GetAuthPolicyReqMsg.m_serviceName = m_GetAuthPolicyReqMsg.m_serviceName.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
case AWAITING_HOST_DATA:
|
||||
// Consume the data
|
||||
m_GetAuthPolicyReqMsg.m_hostName = new String(ch, start, length);
|
||||
@ -234,6 +236,11 @@ public class GetAuthPolicyReqMsg
|
||||
m_state = AWAITING_HOST_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_HOST_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_GetAuthPolicyReqMsg.m_hostName = m_GetAuthPolicyReqMsg.m_hostName.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
|
@ -107,7 +107,6 @@ public class GetAuthTokReqMsg
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.getAuthTokRequestElementName.equals(qName))
|
||||
@ -179,7 +178,6 @@ public class GetAuthTokReqMsg
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.getAuthTokRequestElementName.equals(qName))
|
||||
@ -250,7 +248,6 @@ public class GetAuthTokReqMsg
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_SERVICE_DATA:
|
||||
// Consume the data
|
||||
m_GetAuthTokReqMsg.m_serviceName = new String(ch, start, length);
|
||||
@ -259,6 +256,11 @@ public class GetAuthTokReqMsg
|
||||
m_state = AWAITING_SERVICE_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_SERVICE_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_GetAuthTokReqMsg.m_serviceName = m_GetAuthTokReqMsg.m_serviceName.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
case AWAITING_HOST_DATA:
|
||||
// Consume the data
|
||||
m_GetAuthTokReqMsg.m_hostName = new String(ch, start, length);
|
||||
@ -267,6 +269,11 @@ public class GetAuthTokReqMsg
|
||||
m_state = AWAITING_HOST_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_HOST_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_GetAuthTokReqMsg.m_hostName = m_GetAuthTokReqMsg.m_hostName.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
case AWAITING_SESSION_TOKEN_DATA:
|
||||
// Consume the data
|
||||
m_GetAuthTokReqMsg.m_sessionToken = new String(ch, start, length);
|
||||
@ -275,6 +282,11 @@ public class GetAuthTokReqMsg
|
||||
m_state = AWAITING_SESSION_TOKEN_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_SESSION_TOKEN_ELEMENT_END:
|
||||
// Consume the data
|
||||
m_GetAuthTokReqMsg.m_sessionToken = m_GetAuthTokReqMsg.m_sessionToken.concat(new String(ch, start, length));
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
|
@ -48,7 +48,8 @@ JAVAFILES = ProtoDefs.java \
|
||||
GetAuthTokRespMsg.java \
|
||||
Krb5Authenticate.java \
|
||||
PwdAuthenticate.java \
|
||||
SessionToken.java
|
||||
SessionToken.java \
|
||||
WSSecurity.java
|
||||
|
||||
EXTRA_DIST = $(JAVAFILES) \
|
||||
Krb5_mechanism.settings \
|
||||
|
@ -26,20 +26,26 @@ package com.novell.casa.authtoksvc;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
import org.apache.axis.Message;
|
||||
import org.apache.axis.MessageContext;
|
||||
import org.apache.axis.client.AxisClient;
|
||||
import org.apache.axis.configuration.NullProvider;
|
||||
import org.apache.axis.message.SOAPEnvelope;
|
||||
import org.apache.axis.message.SOAPBody;
|
||||
import org.apache.axis.message.MessageElement;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import java.io.*;
|
||||
|
||||
/*
|
||||
* SessionToken class.
|
||||
*
|
||||
* This class constructs session tokens that Casa clients can present to
|
||||
* the Casa server to prove that an entity has been authenticated to
|
||||
* a particular realm. The format of the session token is as follows:
|
||||
*
|
||||
* <?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
* This class constructs sessions tokens that clients can present to an ATS
|
||||
* to prove that an entity has been authenticated to a particular realm.
|
||||
* The session token consists of a SOAP message secured with WSSecurity
|
||||
* with the appropriate elements signed and with a timestamp. The body of
|
||||
* the SOAP message is as follows:
|
||||
*
|
||||
* <session_token>
|
||||
* <signature>signature value</signature>
|
||||
* <lifetime>lifetime value</lifetime>
|
||||
@ -51,308 +57,47 @@ import org.xml.sax.helpers.XMLReaderFactory;
|
||||
public class SessionToken
|
||||
{
|
||||
|
||||
private String m_id;
|
||||
private String m_realm;
|
||||
private String m_lifetime;
|
||||
private String m_signature;
|
||||
private String m_id = null;
|
||||
private String m_realm = null;
|
||||
private String m_token;
|
||||
|
||||
/*
|
||||
* Class for handling parsing events.
|
||||
*/
|
||||
private class SAXHandler extends org.xml.sax.helpers.DefaultHandler
|
||||
{
|
||||
private final static int AWAITING_ROOT_ELEMENT_START = 0;
|
||||
private final static int AWAITING_ROOT_ELEMENT_END = 1;
|
||||
private final static int AWAITING_SIGNATURE_ELEMENT_START = 2;
|
||||
private final static int AWAITING_SIGNATURE_ELEMENT_END = 3;
|
||||
private final static int AWAITING_SIGNATURE_DATA = 4;
|
||||
private final static int AWAITING_LIFETIME_ELEMENT_START = 5;
|
||||
private final static int AWAITING_LIFETIME_ELEMENT_END = 6;
|
||||
private final static int AWAITING_LIFETIME_DATA = 7;
|
||||
private final static int AWAITING_REALM_ELEMENT_START = 8;
|
||||
private final static int AWAITING_REALM_ELEMENT_END = 9;
|
||||
private final static int AWAITING_REALM_DATA = 10;
|
||||
private final static int AWAITING_IDENT_ID_ELEMENT_START = 11;
|
||||
private final static int AWAITING_IDENT_ID_ELEMENT_END = 12;
|
||||
private final static int AWAITING_IDENT_ID_DATA = 13;
|
||||
private final static int DONE_PARSING = 14;
|
||||
static final String sessionTokenSoapMsg =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<SOAP-ENV:Envelope" +
|
||||
" xmlns:SOAP-ENV=\"http://www.w3.org/2003/05/soap-envelope\"\n" +
|
||||
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
|
||||
" <SOAP-ENV:Body>" +
|
||||
" <session_token><realm></realm><ident_id></ident_id></session_token>" +
|
||||
" </SOAP-ENV:Body>" +
|
||||
"</SOAP-ENV:Envelope>";
|
||||
|
||||
private SessionToken m_SessionToken;
|
||||
private int m_state;
|
||||
static final private MessageContext axisMsgContext = new MessageContext(new AxisClient(new NullProvider()));
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public SAXHandler (SessionToken SessionToken)
|
||||
{
|
||||
super();
|
||||
|
||||
// Initialize our members
|
||||
m_SessionToken = SessionToken;
|
||||
m_state = AWAITING_ROOT_ELEMENT_START;
|
||||
}
|
||||
|
||||
/*
|
||||
* endDocument() implementation.
|
||||
*/
|
||||
public void endDocument () throws SAXException
|
||||
{
|
||||
// Verify that we obtained all of the required elements
|
||||
if (m_state != DONE_PARSING)
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.endDocument()- Missing element");
|
||||
throw new SAXException("Missing element");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* startElement() implementation.
|
||||
*/
|
||||
public void startElement (String uri, String name, String qName, org.xml.sax.Attributes atts) throws SAXException
|
||||
{
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.sessionTokenElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_SIGNATURE_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_SIGNATURE_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.signatureElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_SIGNATURE_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_LIFETIME_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.lifetimeElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_LIFETIME_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AWAITING_REALM_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.realmElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_REALM_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_IDENT_ID_ELEMENT_START:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.identIdElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_IDENT_ID_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.startElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
System.err.println("SessionToken SAXHandler.startElement()- State error");
|
||||
throw new SAXException("State error");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* endElement() immplementation.
|
||||
*/
|
||||
public void endElement (String uri, String name, String qName) throws SAXException
|
||||
{
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_ROOT_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.sessionTokenElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = DONE_PARSING;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_SIGNATURE_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.signatureElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_LIFETIME_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_LIFETIME_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.lifetimeElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_REALM_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_REALM_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.realmElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_IDENT_ID_ELEMENT_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
case AWAITING_IDENT_ID_ELEMENT_END:
|
||||
// Verify that we are processing the expected tag
|
||||
if (ProtoDefs.identIdElementName.equals(qName))
|
||||
{
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_ROOT_ELEMENT_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("SessionToken SAXHandler.endElement()- Un-expected element");
|
||||
throw new SAXException("Un-expected element");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
System.err.println("SessionToken SAXHandler.startElement()- State error");
|
||||
throw new SAXException("State error");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* character() implementation.
|
||||
*/
|
||||
public void characters (char ch[], int start, int length) throws SAXException
|
||||
{
|
||||
// Proceed based on our state
|
||||
switch (m_state)
|
||||
{
|
||||
|
||||
case AWAITING_SIGNATURE_DATA:
|
||||
// Consume the data
|
||||
m_SessionToken.m_signature = new String(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_SIGNATURE_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_LIFETIME_DATA:
|
||||
// Consume the data
|
||||
m_SessionToken.m_lifetime = new String(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_LIFETIME_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_REALM_DATA:
|
||||
// Consume the data
|
||||
m_SessionToken.m_realm = new String(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_REALM_ELEMENT_END;
|
||||
break;
|
||||
|
||||
case AWAITING_IDENT_ID_DATA:
|
||||
// Consume the data
|
||||
m_SessionToken.m_id = new String(ch, start, length);
|
||||
|
||||
// Advance to the next state
|
||||
m_state = AWAITING_IDENT_ID_ELEMENT_END;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public SessionToken(String id, String realm, String lifetime) throws Exception
|
||||
public SessionToken(String id,
|
||||
String realm,
|
||||
String lifetime,
|
||||
SvcConfig svcConfig) throws Exception
|
||||
{
|
||||
// Save copies of the input parameters
|
||||
m_id = id;
|
||||
m_realm = realm;
|
||||
m_lifetime = lifetime;
|
||||
|
||||
// Generate a signature
|
||||
// tbd - Over id, realm, and lifetime data.
|
||||
m_signature = "tbd";
|
||||
// Create SessionTokenMessage
|
||||
Message sessionTokenMessage = getMessage(realm,
|
||||
id,
|
||||
Integer.valueOf(lifetime).intValue(),
|
||||
svcConfig);
|
||||
|
||||
// Get a StringBuffer to help us with the construction of the token
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
// Start building the message
|
||||
sb.append(ProtoDefs.xmlDeclaration + "\r\n");
|
||||
sb.append("<" + ProtoDefs.sessionTokenElementName + ">" + "\r\n");
|
||||
sb.append("<" + ProtoDefs.signatureElementName + ">" + m_signature + "</" + ProtoDefs.signatureElementName + ">" + "\r\n");
|
||||
sb.append("<" + ProtoDefs.lifetimeElementName + ">" + m_lifetime + "</" + ProtoDefs.lifetimeElementName + ">" + "\r\n");
|
||||
sb.append("<" + ProtoDefs.realmElementName + ">" + m_realm + "</" + ProtoDefs.realmElementName + ">" + "\r\n");
|
||||
sb.append("<" + ProtoDefs.identIdElementName + ">" + m_id + "</" + ProtoDefs.identIdElementName + ">" + "\r\n");
|
||||
sb.append("</" + ProtoDefs.sessionTokenElementName + ">" + "\r\n");
|
||||
|
||||
// Save the token
|
||||
m_token = sb.toString();
|
||||
// Now save the message as a string
|
||||
OutputStream outStream = new ByteArrayOutputStream();
|
||||
sessionTokenMessage.writeTo(outStream);
|
||||
m_token = outStream.toString();
|
||||
outStream.close();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -364,30 +109,102 @@ public class SessionToken
|
||||
// Decode the token string
|
||||
m_token = Base64Coder.decode(token);
|
||||
|
||||
// Now parse the token into its elements
|
||||
// Now instantiate a SOAP message with the string
|
||||
InputStream inStream = new ByteArrayInputStream(m_token.getBytes());
|
||||
Message message = new Message(inStream);
|
||||
|
||||
// Get access to the SOAP Envelope
|
||||
SOAPEnvelope envelope = message.getSOAPEnvelope();
|
||||
|
||||
// Verify the message
|
||||
if (WSSecurity.verifyMessage(envelope))
|
||||
{
|
||||
// Message verification succeded, now obtain the realm and identity id
|
||||
// from the message body.
|
||||
SOAPBody body = (SOAPBody) envelope.getBody();
|
||||
QName sessionTokenElementName = new QName("session_token");
|
||||
MessageElement sessionTokenElement = body.getChildElement(sessionTokenElementName);
|
||||
QName realmElementName = new QName("realm");
|
||||
MessageElement realmElement = sessionTokenElement.getChildElement(realmElementName);
|
||||
if (realmElement != null)
|
||||
{
|
||||
m_realm = realmElement.getChildNodes().item(0).getNodeValue();
|
||||
}
|
||||
QName identIdElementName = new QName("ident_id");
|
||||
MessageElement identIdElement = sessionTokenElement.getChildElement(identIdElementName);
|
||||
if (identIdElement != null)
|
||||
{
|
||||
m_id = identIdElement.getChildNodes().item(0).getNodeValue();
|
||||
}
|
||||
|
||||
if (m_realm == null || m_id == null)
|
||||
{
|
||||
System.out.println("SessionToken()- Required data missing from session token");
|
||||
throw new Exception("Error: Required data missing from session Token");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Message verification failed
|
||||
System.err.println("SessionToken()- Invalid Session Token");
|
||||
throw new Exception("Invalid Session Token");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SessionToken SOAP Message
|
||||
*
|
||||
* @param realm String containing the identity token that should be part of the message
|
||||
* @param identityId String containing the identity token type
|
||||
* @param lifetime Lifetime that should be specified in the message timestamp (seconds)
|
||||
* @param svcConfig Service Config object
|
||||
* @return <code>Message<code> SessionToken message, null if the method fails.
|
||||
*/
|
||||
private Message getMessage(String realm,
|
||||
String identityId,
|
||||
int lifetime,
|
||||
SvcConfig svcConfig)
|
||||
{
|
||||
Message secureMessage;
|
||||
|
||||
try
|
||||
{
|
||||
// Parse the SessionToken
|
||||
XMLReader xr = XMLReaderFactory.createXMLReader();
|
||||
SAXHandler handler = new SAXHandler(this);
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
// Build SOAP Message with an identity token in the body
|
||||
//
|
||||
// First create a message and obtain its body
|
||||
InputStream inStream = new ByteArrayInputStream(sessionTokenSoapMsg.getBytes());
|
||||
Message message = new Message(inStream);
|
||||
message.setMessageContext(axisMsgContext);
|
||||
SOAPBody body = (SOAPBody) message.getSOAPBody();
|
||||
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(m_token.getBytes());
|
||||
InputSource source = new InputSource(inStream);
|
||||
xr.parse(source);
|
||||
// Get access to the session_token element
|
||||
QName sessionTokenElementName = new QName("session_token");
|
||||
MessageElement sessionTokenElement = body.getChildElement(sessionTokenElementName);
|
||||
|
||||
// Verify the signature
|
||||
// tbd
|
||||
// Get access to the realm element and set its value
|
||||
QName realmElementName = new QName("realm");
|
||||
MessageElement realmElement = sessionTokenElement.getChildElement(realmElementName);
|
||||
realmElement.addTextNode(realm);
|
||||
|
||||
// Verify that the token has not expired
|
||||
// tbd
|
||||
// Get access to the ident_id element and set its value
|
||||
QName identIdElementName = new QName("ident_id");
|
||||
MessageElement identIdElement = sessionTokenElement.getChildElement(identIdElementName);
|
||||
identIdElement.addTextNode(identityId);
|
||||
|
||||
// Now we need to secure the SOAP message that we created, we are doing to
|
||||
// do so by adding a timestamp and signing the timestamp as well as the body.
|
||||
// To do this we are going to leverage WS-Security.
|
||||
secureMessage = WSSecurity.secureSOAPEnvelope(message.getSOAPEnvelope(),
|
||||
lifetime,
|
||||
svcConfig);
|
||||
}
|
||||
catch (SAXException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
System.err.println("SessionToken()- Parse exception: " + e.toString());
|
||||
throw new Exception("Protocol error");
|
||||
System.out.println("SessionToken.getMessage() - Exception caught building message, error: " + e.getMessage());
|
||||
secureMessage = null;
|
||||
}
|
||||
|
||||
return secureMessage;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -53,6 +53,8 @@ public class SvcConfig
|
||||
public final static String ConfigFolderPath = "ConfigFolderPath";
|
||||
public final static String AppRootPath = "AppRootPath";
|
||||
public final static String ReconfigureInterval = "ReconfigureInterval";
|
||||
public final static String KeyStoreUser = "KeyStoreUser";
|
||||
public final static String KeyStorePwd = "KeyStorePwd";
|
||||
|
||||
// Default configuration values
|
||||
public final static String DefaultSessionTokenLifetimeValue = "43200"; // Seconds
|
||||
|
@ -0,0 +1,274 @@
|
||||
/***********************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Novell, Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail,
|
||||
* you may find current contact information at www.novell.com.
|
||||
*
|
||||
* Author: Juan Carlos Luciani <jluciani@novell.com>
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
package com.novell.casa.authtoksvc;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import org.apache.axis.Message;
|
||||
import org.apache.axis.message.SOAPEnvelope;
|
||||
import org.apache.ws.security.*;
|
||||
import org.apache.ws.security.components.crypto.Crypto;
|
||||
import org.apache.ws.security.components.crypto.CryptoFactory;
|
||||
import org.apache.ws.security.message.WSSecHeader;
|
||||
import org.apache.ws.security.message.WSSecSignature;
|
||||
import org.apache.ws.security.message.WSSecTimestamp;
|
||||
import org.apache.xml.security.c14n.Canonicalizer;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import javax.xml.soap.MessageFactory;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/*
|
||||
* WSSecurity Class.
|
||||
*
|
||||
* This class provides static methods for securing and verifying SOAP messages. SOAP messages
|
||||
* are secured by adding a timestamp and signing the appropriate elements using methods and
|
||||
* headers defined by WS* specifications.
|
||||
*
|
||||
*/
|
||||
public class WSSecurity
|
||||
{
|
||||
static final private WSSecurityEngine secEngine = new WSSecurityEngine();
|
||||
static final private Crypto crypto = CryptoFactory.getInstance();
|
||||
|
||||
/**
|
||||
* Creates a SOAP message from a document.
|
||||
*
|
||||
*/
|
||||
private static Message toSOAPMessage(Document doc) throws Exception
|
||||
{
|
||||
Canonicalizer c14n = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
|
||||
byte[] canonicalMessage = c14n.canonicalizeSubtree(doc);
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(canonicalMessage);
|
||||
MessageFactory factory = MessageFactory.newInstance();
|
||||
return (org.apache.axis.Message) factory.createMessage(null, in);
|
||||
}
|
||||
|
||||
/***
|
||||
* Returns the first element that containes an Id with value
|
||||
* <code>uri</code> and <code>namespace</code>.
|
||||
* <p/>
|
||||
*
|
||||
* Copyright Note: The code for this function was copied from file
|
||||
* WSSecurityUtil.java from package org.apache.ws.security.util.
|
||||
* The Copyright notice on this file is as follows:
|
||||
*
|
||||
* Copyright 2003-2006 The Apache Software Foundation, or their licensors, as
|
||||
* appropriate.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param startNode Where to start the search
|
||||
* @param value Value of the Id attribute
|
||||
* @param namespace Namespace URI of the Id
|
||||
* @return The found element or <code>null</code>
|
||||
*/
|
||||
private static Element findElementById(Node startNode,
|
||||
String value,
|
||||
String namespace)
|
||||
{
|
||||
// Just return null if startNode is set to null
|
||||
if (startNode == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Node startParent = startNode.getParentNode();
|
||||
Node processedNode;
|
||||
while (startNode != null)
|
||||
{
|
||||
// start node processing at this point
|
||||
if (startNode.getNodeType() == Node.ELEMENT_NODE)
|
||||
{
|
||||
Element se = (Element) startNode;
|
||||
if (se.hasAttributeNS(namespace, "Id")
|
||||
&& value.equals(se.getAttributeNS(namespace, "Id")))
|
||||
{
|
||||
return se;
|
||||
}
|
||||
}
|
||||
|
||||
processedNode = startNode;
|
||||
startNode = startNode.getFirstChild();
|
||||
|
||||
// no child, this node is done.
|
||||
if (startNode == null)
|
||||
{
|
||||
// close node processing, get sibling
|
||||
startNode = processedNode.getNextSibling();
|
||||
}
|
||||
|
||||
// no more siblings, get parent, all children
|
||||
// of parent are processed.
|
||||
while (startNode == null)
|
||||
{
|
||||
processedNode = processedNode.getParentNode();
|
||||
if (processedNode == startParent)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// close parent node processing (processed node now)
|
||||
startNode = processedNode.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies SOAP envelope timestamp and signatures.
|
||||
*
|
||||
* @param envelope SOAP envelope with timestamp
|
||||
* @return <code>boolean</code> True if verification succeeds
|
||||
* @throws Exception on error
|
||||
*/
|
||||
public static boolean verifyMessage(SOAPEnvelope envelope) throws Exception
|
||||
{
|
||||
boolean msgVerificationStatus = false;
|
||||
|
||||
try
|
||||
{
|
||||
boolean timeStampProcessed = false;
|
||||
boolean signatureProcessed = false;
|
||||
Vector<WSSecurityEngineResult> results;
|
||||
Document signedDoc = envelope.getAsDocument();
|
||||
results = secEngine.processSecurityHeader(signedDoc, null, null, crypto);
|
||||
if (results != null)
|
||||
{
|
||||
for (WSSecurityEngineResult result : results)
|
||||
{
|
||||
if (result.getAction() == WSConstants.TS)
|
||||
{
|
||||
timeStampProcessed = true;
|
||||
}
|
||||
else if (result.getAction() == WSConstants.SIGN)
|
||||
{
|
||||
// A signature was processed, verify that the signature was over the timestamp
|
||||
// and the body.
|
||||
boolean timeStampSigned = false;
|
||||
boolean bodySigned = false;
|
||||
Set signedElements = result.getSignedElements();
|
||||
for (Object signedElement : signedElements)
|
||||
{
|
||||
String elementId = (String) signedElement;
|
||||
Element element = findElementById(signedDoc.getDocumentElement(), elementId, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
|
||||
if (element != null)
|
||||
{
|
||||
if ("wsu:Timestamp".equalsIgnoreCase(element.getNodeName()))
|
||||
{
|
||||
timeStampSigned = true;
|
||||
}
|
||||
else if ("SOAP-ENV:Body".equalsIgnoreCase(element.getNodeName()))
|
||||
{
|
||||
bodySigned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timeStampSigned && bodySigned)
|
||||
{
|
||||
signatureProcessed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timeStampProcessed && signatureProcessed)
|
||||
{
|
||||
System.out.println("WSSecurity.verifyMessage() - Validation succeded");
|
||||
msgVerificationStatus = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("WSSecurity.verifyMessage() - validation failed");
|
||||
}
|
||||
}
|
||||
catch (WSSecurityException e)
|
||||
{
|
||||
System.out.println("WSSecurity.verifyMessage() - Verification failed with error:" + e.getMessage() + " code = " + e.getErrorCode());
|
||||
}
|
||||
|
||||
return msgVerificationStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add timestamp and sign SOAP message in compliance with WS-Security.
|
||||
*
|
||||
* @param envelope String containing a SOAP envelope
|
||||
* @param timeToLive Value to set the timestamp timeToLive parameter in seconds
|
||||
* @param svcConfig Service Config object
|
||||
* @return <code>Message</code> Signed and timestamped SOAP message
|
||||
* @throws Exception on error
|
||||
*/
|
||||
public static Message secureSOAPEnvelope(SOAPEnvelope envelope,
|
||||
int timeToLive,
|
||||
SvcConfig svcConfig) throws Exception
|
||||
{
|
||||
WSSecSignature signer = new WSSecSignature();
|
||||
signer.setUserInfo(svcConfig.getSetting(SvcConfig.KeyStoreUser),
|
||||
svcConfig.getSetting(SvcConfig.KeyStorePwd));
|
||||
signer.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER); // Include X509 Cert in message
|
||||
|
||||
Document doc = envelope.getAsDocument();
|
||||
|
||||
WSSecHeader secHeader = new WSSecHeader();
|
||||
secHeader.insertSecurityHeader(doc);
|
||||
|
||||
WSSecTimestamp timeStamper = new WSSecTimestamp();
|
||||
timeStamper.setTimeToLive(timeToLive);
|
||||
timeStamper.build(doc, secHeader);
|
||||
|
||||
Vector<WSEncryptionPart> parts = new Vector<WSEncryptionPart>();
|
||||
|
||||
String soapNamespace = doc.getDocumentElement().getNamespaceURI();
|
||||
WSEncryptionPart bodyPart = new WSEncryptionPart("Body", soapNamespace, "");
|
||||
parts.add(bodyPart);
|
||||
|
||||
WSEncryptionPart timeStampPart = new WSEncryptionPart(timeStamper.getId());
|
||||
parts.add(timeStampPart);
|
||||
|
||||
signer.setParts(parts);
|
||||
|
||||
Document signedDoc = signer.build(doc, crypto, secHeader);
|
||||
|
||||
// Convert the signed document into a SOAP message and return it.
|
||||
return toSOAPMessage(signedDoc);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user