Omaha #3350 Added user/role authentication. Added XACML authorization

Change-Id: Id307fdc04ba7a74c9e81650c7b4ba272405cf6df

Former-commit-id: 91df842c4c [formerly c74f855d31] [formerly d4997f5a90] [formerly d4997f5a90 [formerly cebfbebea6]] [formerly 6cb73e63a1 [formerly d4997f5a90 [formerly cebfbebea6] [formerly 6cb73e63a1 [formerly 81d0249971d4004067b6aef672e00417ddb83b36]]]]
Former-commit-id: 6cb73e63a1
Former-commit-id: 0d4bf0bbab90c26bb30b41f76341cecea18b3ad9 [formerly b6f1310c23e3d57c8b4d89aa6e6c01e283285ca6] [formerly 6959bdcdb2 [formerly 576e2eb0f8]]
Former-commit-id: 6959bdcdb2
Former-commit-id: 2971b9f0f2
This commit is contained in:
Benjamin Phillippe 2014-07-10 13:58:05 -05:00
parent 45ce12b118
commit afd3fd8503
44 changed files with 1750 additions and 326 deletions

View file

@ -43,4 +43,11 @@
install-size="0"
version="0.0.0"/>
<plugin
id="com.raytheon.uf.common.security"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

View file

@ -1,15 +1,20 @@
#!/bin/bash
SETUP_ENV=/awips2/edex/bin/setup.env
source $SETUP_ENV
JAVA_BIN=/awips2/java/jre/bin/java
securityDir=/awips2/edex/conf/security
securityProps=$securityDir/security.properties
securityPropertiesDir=/awips2/edex/conf/resources/site/$AW_SITE_IDENTIFIER
securityProps=$securityPropertiesDir/security.properties
publicKeyFile=PublicKey.cer
keystore=keystore.jks
truststore=truststore.jks
keystorePw=
keyAlias=$(hostname -s)
keyPw=
encryptionKey=encrypt
truststorePw=password
function usage {
@ -23,10 +28,34 @@ function generateKeystores() {
echo "Generating keystores"
if [ -z $CLUSTER_ID ]
then
echo "CLUSTER_ID undefined. Determining from hostname..."
HOST=$(hostname -s)
CLUSTER_ID=${HOST:$(expr index "$HOST" -)} | tr '[:lower:]' '[:upper:]'
fi
if [ -z $CLUSTER_ID ]
then
echo "CLUSTER_ID could not be determined from hostname. Using site as CLUSTER_ID"
CLUSTER_ID=$AW_SITE_IDENTIFIER
fi
echo "CLUSTER_ID set to: $CLUSTER_ID"
keyAlias=$CLUSTER_ID
# Write the cluster ID to the setup.env file
sed -i "s@^export CLUSTER_ID.*@export CLUSTER_ID=$CLUSTER_ID@g" $SETUP_ENV
if [ ! -d "$securityDir" ]; then
mkdir $securityDir
fi
if [ ! -d "$securityPropertiesDir" ]; then
mkdir -p $securityPropertiesDir
fi
while [ -z $keystorePw ];
do
echo -n "Enter desired password for keystore [$keystore]: "
@ -74,20 +103,29 @@ keytool -genkeypair -alias $keyAlias -keypass $keyPw -keystore $keystore -storep
echo -n "Exporting public key..."
exportOutput=`keytool -exportcert -alias $keyAlias -keystore $keystore -file $keyAlias$publicKeyFile -storepass $keystorePw 2>&1`
echo "Done!"
obfuscatedKeystorePassword=`java -cp /awips2/edex/lib/dependencies/org.eclipse.jetty/jetty-http-7.6.14.v20131031.jar:/awips2/edex/lib/dependencies/org.eclipse.jetty/jetty-util-7.6.14.v20131031.jar org.eclipse.jetty.util.security.Password $keystorePw 2>&1 | grep OBF`
obfuscatedKeystorePassword=`$JAVA_BIN -cp /awips2/edex/lib/dependencies/org.apache.commons.codec/commons-codec-1.4.jar:/awips2/edex/lib/plugins/com.raytheon.uf.common.security.jar com.raytheon.uf.common.security.encryption.AESEncryptor encrypt $encryptionKey $keystorePw 2>&1`
echo "Generating trust store..."
keytool -genkey -alias tmp -keypass tempPass -dname CN=foo -keystore $truststore -storepass $truststorePw
keytool -delete -alias tmp -keystore $truststore -storepass $truststorePw
keytool -import -trustcacerts -file $keyAlias$publicKeyFile -alias $keyAlias -keystore $truststore -storepass $truststorePw
obfuscatedTruststorePassword=`java -cp /awips2/edex/lib/dependencies/org.eclipse.jetty/jetty-http-7.6.14.v20131031.jar:/awips2/edex/lib/dependencies/org.eclipse.jetty/jetty-util-7.6.14.v20131031.jar org.eclipse.jetty.util.security.Password $truststorePw 2>&1 | grep OBF`
jettyObscuredPassword=`$JAVA_BIN -cp /awips2/edex/lib/dependencies/org.eclipse.jetty/jetty-http-7.6.14.v20131031.jar:/awips2/edex/lib/dependencies/org.eclipse.jetty/jetty-util-7.6.14.v20131031.jar org.eclipse.jetty.util.security.Password $keystorePw 2>&1 | grep OBF`
obfuscatedTruststorePassword=`$JAVA_BIN -cp /awips2/edex/lib/dependencies/org.apache.commons.codec/commons-codec-1.4.jar:/awips2/edex/lib/plugins/com.raytheon.uf.common.security.jar com.raytheon.uf.common.security.encryption.AESEncryptor encrypt $encryptionKey $truststorePw 2>&1`
echo -n "Generating security properties file..."
echo "edex.security.keystore.path=$securityDir/$keystore" > $securityProps
echo "# This file was automatically generated using /awips2/edex/conf/security/keystoreUtil.sh" > $securityProps
echo "java.security.auth.login.config=/awips2/edex/conf/security/realms.properties" >> $securityProps
echo "edex.security.auth.user=$keyAlias" >> $securityProps
echo "edex.security.auth.password=$obfuscatedKeystorePassword" >> $securityProps
echo "edex.security.auth.authorizationType=Basic" >> $securityProps
echo "edex.security.auth.loginService.name=RegistryRealm" >> $securityProps
echo "edex.security.auth.loginService.realm=RegistryRealm" >> $securityProps
echo "edex.security.encryption.key=$encryptionKey" >> $securityProps
echo "edex.security.keystore.path=$securityDir/$keystore" >> $securityProps
echo "edex.security.keystore.alias=$keyAlias" >> $securityProps
echo "edex.security.keystore.password=$obfuscatedKeystorePassword" >> $securityProps
echo "edex.security.keystore.type=JKS" >> $securityProps
@ -100,7 +138,7 @@ echo "edex.security.disableCNCheck=false" >>$securityProps
echo "#The following configuration items are used with the wss4j in/out interceptors" >> $securityProps
echo "org.apache.ws.security.crypto.merlin.keystore.file=security/$keystore" >> $securityProps
echo "org.apache.ws.security.crypto.merlin.keystore.password=$obfuscatedKeystorePassword" >> $securityProps
echo "org.apache.ws.security.crypto.merlin.keystore.password=$jettyObscuredPassword" >> $securityProps
echo "org.apache.ws.security.crypto.merlin.keystore.type=JKS" >> $securityProps
echo "org.apache.ws.security.crypto.merlin.keystore.alias=$keyAlias" >> $securityProps

View file

@ -0,0 +1,4 @@
RegistryRealm {
com.raytheon.uf.edex.registry.ebxml.web.security.RegistryLoginModule required
debug="false";
};

View file

@ -54,7 +54,6 @@ import com.raytheon.uf.common.registry.ebxml.slots.SlotConverter;
import com.raytheon.uf.common.registry.ebxml.slots.StringSlotConverter;
import com.raytheon.uf.common.serialization.SerializationException;
import com.raytheon.uf.common.time.util.ImmutableDate;
import com.raytheon.uf.common.util.ClusterIdUtil;
import com.raytheon.uf.common.util.CollectionUtil;
import com.raytheon.uf.common.util.ReflectionException;
import com.raytheon.uf.common.util.ReflectionUtil;
@ -84,6 +83,7 @@ import com.raytheon.uf.common.util.ReflectionUtil;
* Apr 24, 2014 2992 dhladky fixed all objects in ebxml owned by NCF, bad.
* 6/5/2014 1712 bphillip Registry now communicates over https
* June 25, 2014 3273 dhladky Remove all DD environment variables from setup.env
* 7/10/2014 1717 bphillip Changed default user
*
* </pre>
*
@ -104,7 +104,7 @@ public final class RegistryUtil {
public static final String registryUser = "Registry";
public static final String defaultUser = "NCF";
public static final String defaultUser = RegistryObjectType.SYSTEM_USER;
static {
if (System.getProperty("ebxml.registry.host") != null
@ -121,7 +121,7 @@ public final class RegistryUtil {
/**
* The default internal owner is the local registry ID
*/
public static final String DEFAULT_OWNER = ClusterIdUtil.getId();
public static final String DEFAULT_OWNER = defaultUser;
// A private mapping of attribute types to slot types, used when storing an
// object to the registry to map QueryableAttributes to SlotConverters.

View file

@ -93,6 +93,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
* 2012 bphillip Initial implementation
* 10/17/2013 1682 bphillip Added software history
* 12/2/2013 1829 bphillip Made ExtensibleObjectType persistable, modified persistence annotations, added hashCode, toString and equals
* 7/10/2014 1717 bphillip Added default user
* </pre>
*
* @author bphillip
@ -123,6 +124,8 @@ public class RegistryObjectType extends IdentifiableType {
private static final long serialVersionUID = -7436174012584469534L;
public static final String SYSTEM_USER = "System";
@XmlElement(name = "Name")
@DynamicSerializeElement
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@ -172,7 +175,7 @@ public class RegistryObjectType extends IdentifiableType {
@XmlAttribute
@DynamicSerializeElement
protected String owner;
protected String owner = SYSTEM_USER;
@XmlAttribute
@DynamicSerializeElement

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.raytheon.uf.common.security</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,9 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Security
Bundle-SymbolicName: com.raytheon.uf.common.security
Bundle-Version: 1.14.0.qualifier
Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Require-Bundle: org.apache.commons.codec;bundle-version="1.4.0"
Export-Package: com.raytheon.uf.common.security.encryption

View file

@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.

View file

@ -0,0 +1,152 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.security.encryption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
*
* Class that supports encrypting/decrypting AES encrypted objects
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 7/16/2014 3350 bphillip Initial coding
* </pre>
*
* @author bphillip
* @version 1
*/
public class AESEncryptor {
private static final String ALGORITHM = "AES";
private static final String PADDING = "AES/CFB8/NoPadding";
// entropy input vector length
private static final int IV_LENGTH = 16;
private IvParameterSpec ivSpec;
private SecretKeySpec key;
private Cipher deCipher;
private Cipher enCipher;
public static void main(String[] args) {
String action = args[0];
String key = args[1];
String input = args[2];
try {
AESEncryptor enc = new AESEncryptor();
if (action.equalsIgnoreCase("encrypt")) {
System.out.println(enc.encrypt(key, input));
} else if (action.equalsIgnoreCase("decrypt")) {
System.out.println(enc.decrypt(key, input));
} else {
System.out.println("Unrecognized action");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public AESEncryptor() {
}
/**
* Sets up the cipher using the sharedKey
*
* @param sharedKey
* @throws NoSuchAlgorithmException
*/
private void setupCipher(String sharedKey) throws Exception {
byte[] keyBytes = null;
MessageDigest sha = MessageDigest.getInstance("SHA-1");
keyBytes = sha.digest(Base64.decodeBase64(sharedKey));
keyBytes = Arrays.copyOf(keyBytes, IV_LENGTH); // use only first 128 bit
byte[] ivBytes = new byte[IV_LENGTH];
ivSpec = new IvParameterSpec(ivBytes);
/*
* create the cipher with the algorithm you choose see javadoc for
* Cipher class for more info, e.g.
*/
key = new SecretKeySpec(keyBytes, ALGORITHM);
deCipher = Cipher.getInstance(PADDING);
enCipher = Cipher.getInstance(PADDING);
}
/**
* Encrypts a string using AES/DES encoding
*
* @param sharedKey
* The encryption key
* @param password
* The string to encrypt
* @return The encrypted string
* @throws Exception
* on error
*/
public String encrypt(String sharedKey, String password) throws Exception {
setupCipher(sharedKey);
enCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
return Base64.encodeBase64String(enCipher.doFinal(password.getBytes()));
}
/**
* Decrypts an AES/DES encoded string
*
* @param sharedKey
* The encryption key
* @param encryptedPass
* The encrypted string to decrypt
* @return The encrypted string
* @throws Exception
* on error
*/
public String decrypt(String sharedKey, String encryptedPass)
throws Exception {
setupCipher(sharedKey);
deCipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
return new String(deCipher.doFinal(Base64.decodeBase64(encryptedPass)));
}
}

View file

@ -35,8 +35,10 @@ Require-Bundle: com.raytheon.uf.common.registry.schemas.ebxml;bundle-version="1.
com.sun.xml.bind;bundle-version="1.0.0",
org.eclipse.jetty;bundle-version="7.6.14",
com.raytheon.uf.edex.security;bundle-version="1.14.0",
org.opensaml;bundle-version="1.0.0"
Export-Package: com.raytheon.uf.edex.registry.ebxml.acp,
org.opensaml;bundle-version="1.0.0",
com.raytheon.uf.common.security;bundle-version="1.14.0"
Export-Package: com.raytheon.uf.edex.registry.ebxml,
com.raytheon.uf.edex.registry.ebxml.acp,
com.raytheon.uf.edex.registry.ebxml.dao,
com.raytheon.uf.edex.registry.ebxml.exception,
com.raytheon.uf.edex.registry.ebxml.init,

View file

@ -19,6 +19,10 @@
<constructor-arg ref="RegistryGarbageCollector" />
</bean>
<bean factory-bean="eventBus" factory-method="register">
<constructor-arg ref="credentialCache" />
</bean>
<!-- TODO: This is a sample external endpoint for registry events.
It is dormant as long as the ${registry.event.external.publish} prop
is set to false. Which by default until Hazard Services uses this, will be.

View file

@ -2,6 +2,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="encryption" class="com.raytheon.uf.common.security.encryption.AESEncryptor"/>
<bean id="edexRegistryManagerFactory"
class="com.raytheon.uf.edex.registry.ebxml.util.EDEXRegistryManagerFactory">
<property name="queryManager" ref="queryServiceImpl" />
@ -17,7 +19,6 @@
<bean id="edexRegistryManager"
class="com.raytheon.uf.edex.registry.ebxml.util.EDEXRegistryManager">
<property name="xacmlPep" ref="XACMLPolicyEnforcementPoint" />
<property name="registryHandler" ref="registryHandler" />
</bean>
@ -64,4 +65,12 @@
<constructor-arg ref="registryObjectDao" />
</bean>
<bean id="registryUsers" class="com.raytheon.uf.edex.registry.ebxml.RegistryUsers">
<property name="personDao" ref="personDao"/>
<property name="roleDao" ref="roleDao"/>
<property name="lcm" ref="lcmServiceImpl"/>
<property name="encryption" ref="encryption" />
<property name="securityConfig" ref="securityConfiguration"/>
</bean>
</beans>

View file

@ -5,7 +5,8 @@
<bean id="DbInit" class="com.raytheon.uf.edex.registry.ebxml.dao.DbInit">
<property name="dao" ref="registryObjectDao" />
<property name="sessionFactory" ref="metadataSessionFactory" />
<property name="lcm" ref="lcmServiceImpl" />
<property name="lcm" ref="lcmServiceImpl" />
<property name="xacmlPolicyAdmin" ref="XACMLPolicyAdministrator"/>
</bean>

View file

@ -3,6 +3,16 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="credentialCache"
class="com.raytheon.uf.edex.registry.ebxml.web.security.CredentialCache"
factory-method="getInstance">
<property name="restServices" ref="registryRestClient" />
<property name="personDao" ref="personDao" />
<property name="txTemplate" ref="metadataTxTemplate" />
<property name="securityConfig" ref="securityConfiguration"/>
<property name="encryption" ref="encryption"/>
</bean>
<bean id="registryRestClient"
class="com.raytheon.uf.edex.registry.ebxml.services.RegistryRESTServices">
<property name="serviceConfig" ref="RegistryServiceConfig" />
@ -21,6 +31,16 @@
<bean id="webServiceInInterceptor"
class="com.raytheon.uf.edex.registry.ebxml.services.RegistryServiceInInterceptor" />
<bean id="xacmlInterceptor" class="com.raytheon.uf.edex.registry.acp.xacml.XACMLInterceptor">
<constructor-arg ref="XACMLPolicyAdministrator"/>
<constructor-arg ref="XACMLPolicyDecisionPoint"/>
</bean>
<bean id="authenticationInterceptor" class="org.apache.cxf.interceptor.security.JAASLoginInterceptor">
<property name="contextName" value="RegistryRealm"/>
</bean>
<bean id="securityOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
@ -28,8 +48,8 @@
<entry key="enableNonceCache" value="false" />
<entry key="enableTimestampCache" value="false" />
<entry key="enableSamlOneTimeUseCache" value="false" />
<entry key="action" value="Signature" />
<entry key="user" value="${ebxml.registry.user}" />
<entry key="action" value="UsernameToken Signature" />
<entry key="user" value="${edex.security.keystore.alias}" />
<entry key="signaturePropRefId" value="propRef"/>
<entry key="propRef" value-ref="encryptedPropertyLoader"/>
<entry key="passwordCallbackClass"
@ -41,22 +61,6 @@
</constructor-arg>
</bean>
<bean id="securityInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="enableNonceCache" value="false" />
<entry key="enableTimestampCache" value="false" />
<entry key="enableSamlOneTimeUseCache" value="false" />
<entry key="action" value="Signature" />
<entry key="signaturePropRefId" value="propRef"/>
<entry key="propRef" value-ref="encryptedPropertyLoader"/>
<entry key="passwordCallbackClass"
value="com.raytheon.uf.edex.registry.ebxml.acp.PasswordCallback" />
<entry key="signatureAlgorithm" value="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
</map>
</constructor-arg>
</bean>
<!-- QUERY -->
<bean id="queryServiceImpl"
class="com.raytheon.uf.edex.registry.ebxml.services.query.QueryManagerImpl">

View file

@ -2,10 +2,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="XACMLPolicyEnforcementPoint"
class="com.raytheon.uf.edex.registry.acp.xacml.XACMLPolicyEnforcementPoint">
<property name="xacmlContextHandler" ref="XACMLContextHandler" />
</bean>
<bean id="XACMLPolicyDecisionPoint" class="com.raytheon.uf.edex.registry.acp.xacml.XACMLPolicyDecisionPoint"/>
<bean id="XACMLContextHandler"
class="com.raytheon.uf.edex.registry.acp.xacml.XACMLContextHandler">

View file

@ -20,8 +20,6 @@ ebxml.thrift.service.port=9588
ebxml.registry.webserver.port=8082
# EBXML registry host
ebxml.registry.host=localhost
# EBXML registry user
ebxml.registry.user=localhost
# EBXML federation enable flag
ebxml.registry.federation.enabled=false
# EBXML registry webserver home

View file

@ -51,7 +51,7 @@ import org.opensaml.xacml.ctx.impl.AttributeValueTypeImplBuilder;
import org.opensaml.xacml.ctx.impl.RequestTypeImplBuilder;
import org.opensaml.xacml.ctx.impl.ResourceTypeImplBuilder;
import org.opensaml.xacml.ctx.impl.SubjectTypeImplBuilder;
import org.opensaml.xacml.policy.ObligationType;
import org.opensaml.xacml.policy.PolicyType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -63,8 +63,6 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.edex.registry.acp.xacml.conformance.DataTypes;
import com.raytheon.uf.edex.registry.acp.xacml.conformance.Identifiers;
import com.raytheon.uf.edex.registry.acp.xacml.engine.obligation.XACMLObligationEvaluator;
import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLException;
import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLNotApplicableException;
import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLProcessingException;
import com.raytheon.uf.edex.registry.acp.xacml.util.XACMLObjectUtil;
@ -91,6 +89,7 @@ import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil;
* 3/18/2013 1802 bphillip Modified to use transaction boundaries and spring injection
* 4/9/2013 1802 bphillip Added additional object checking
* 10/23/2013 1538 bphillip Changed constructor call for QueryRequest
* 7/10/2014 1717 bphillip Removed obligation processing from authorize method
* </pre>
*
* @author bphillip
@ -129,25 +128,10 @@ public class XACMLContextHandler {
throws MsgRegistryException, EbxmlRegistryException {
RequestType request = constructRequest(userName, object);
XACMLObject policy = xacmlPolicyAdmin
.getPolicyObject("urn:oasis:names:tc:xacml:2.0:data-delivery:default-policySet");
XACMLPolicyDecisionPoint pdp = new XACMLPolicyDecisionPoint(policy,
request);
ResponseType response = pdp.evaluate();
List<ObligationType> obligations = pdp.getObligations();
if (obligations != null) {
for (ObligationType obligation : obligations) {
try {
XACMLObligationEvaluator.getInstance().evaluate(obligation,
request);
} catch (XACMLException e) {
e.printStackTrace();
}
}
}
XACMLPolicyDecisionPoint pdp = new XACMLPolicyDecisionPoint(policy);
ResponseType response = pdp.evaluate((PolicyType)policy,request);
return response;
}
@ -355,6 +339,9 @@ public class XACMLContextHandler {
attrName = attrTokens[attrTokens.length - 1];
}
if(attrName.equals("id")){
return objId.toString();
}
Object repoItem = registryObjectDao.getById(objId.toString());
if (repoItem == null) {

View file

@ -0,0 +1,128 @@
package com.raytheon.uf.edex.registry.acp.xacml;
import java.io.ByteArrayOutputStream;
import java.security.Principal;
import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.MsgRegistryException;
import org.apache.cxf.message.Message;
import org.apache.cxf.rt.security.xacml.AbstractXACMLAuthorizingInterceptor;
import org.opensaml.xacml.ctx.RequestType;
import org.opensaml.xacml.ctx.ResponseType;
import org.opensaml.xacml.ctx.ResultType;
import org.opensaml.xacml.policy.ObligationType;
import org.opensaml.xacml.policy.ObligationsType;
import org.opensaml.xacml.policy.PolicySetType;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.edex.registry.acp.xacml.engine.obligation.XACMLObligationEvaluator;
import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLException;
/**
*
*
* Policy enforcement point (PEP) - The system entity that performs access
* control, by making decision requests and enforcing authorization decisions.
* This term is defined in a joint effort by the IETF Policy Framework Working
* Group and the Distributed Management Task Force (DMTF)/Common Information
* Model (CIM) in [RFC3198]. This term corresponds to "Access Enforcement
* Function" (AEF) in [ISO10181-3].
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 7/09/2014 724 bphillip Initial Coding
* </pre>
*
* @author bphillip
* @version 1
*/
public class XACMLInterceptor extends AbstractXACMLAuthorizingInterceptor {
/** The logger */
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(XACMLInterceptor.class);
private XACMLPolicyAdministrator xacmlPolicyAdmin;
private XACMLPolicyDecisionPoint pdp;
public XACMLInterceptor(XACMLPolicyAdministrator xacmlPolicyAdmin,
XACMLPolicyDecisionPoint pdp) throws MsgRegistryException {
this.xacmlPolicyAdmin = xacmlPolicyAdmin;
this.pdp = pdp;
}
@Override
public ResponseType performRequest(RequestType request, Message message)
throws Exception {
if(statusHandler.isPriorityEnabled(Priority.DEBUG)){
statusHandler.debug(outputRequest(request));
}
PolicySetType defaultPolicy = xacmlPolicyAdmin
.getPolicySet("urn:oasis:names:tc:xacml:2.0:data-delivery:default-policySet");
ResponseType response = pdp.evaluate(defaultPolicy, request);
return response;
}
/**
* Handle any Obligations returned by the PDP
*
* @throws XACMLException
*/
protected void handleObligations(RequestType request, Principal principal,
Message message, ResultType result) throws XACMLException {
ObligationsType obligationObject = result.getObligations();
if (obligationObject != null
&& !obligationObject.getObligations().isEmpty()) {
statusHandler.info("Evaluating "
+ obligationObject.getObligations().size()
+ " obligations!");
for (ObligationType obligation : result.getObligations()
.getObligations()) {
XACMLObligationEvaluator.getInstance().evaluate(obligation,
request);
}
}
}
private String outputRequest(XMLObject xmlObject) throws Exception {
try {
System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
MarshallerFactory marshallerFactory = org.opensaml.xml.Configuration
.getMarshallerFactory();
Marshaller marshaller = marshallerFactory.getMarshaller(xmlObject);
Element element = marshaller.marshall(xmlObject);
ByteArrayOutputStream byteArrayOutputStrm = new ByteArrayOutputStream();
DOMImplementationRegistry registry = DOMImplementationRegistry
.newInstance();
DOMImplementationLS impl = (DOMImplementationLS) registry
.getDOMImplementation("LS");
LSSerializer writer = impl.createLSSerializer();
LSOutput output = impl.createLSOutput();
output.setByteStream(byteArrayOutputStrm);
writer.write(element, output);
return byteArrayOutputStrm.toString();
} catch (Exception e) {
throw new Exception("Error Serializing the SAML Response", e);
}
}
}

View file

@ -49,7 +49,6 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.edex.registry.acp.xacml.util.XACMLParser;
import com.raytheon.uf.edex.registry.ebxml.dao.ExtrinsicObjectDao;
import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException;
import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener;
import com.raytheon.uf.edex.registry.ebxml.services.lifecycle.LifecycleManagerImpl;
import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil;
@ -68,6 +67,7 @@ import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil;
* 4/9/2013 1802 bphillip Import changes due to moved constant classes
* 5/21/2013 2022 bphillip Implemented RegistryInitializedListener
* Mar 31, 2014 2889 dhladky Added username for notification center tracking.
* 7/10/2014 1717 bphillip No longer implements RegistryInitializedListener
* </pre>
*
* @author bphillip
@ -75,7 +75,7 @@ import com.raytheon.uf.edex.registry.ebxml.util.EbxmlObjectUtil;
*/
@Service
@Transactional
public class XACMLPolicyAdministrator implements RegistryInitializedListener {
public class XACMLPolicyAdministrator {
/** The status handler */
private static final transient IUFStatusHandler statusHandler = UFStatus
@ -183,16 +183,6 @@ public class XACMLPolicyAdministrator implements RegistryInitializedListener {
return policySet;
}
@Override
public void executeAfterRegistryInit() throws EbxmlRegistryException {
try {
loadAccessControlPolicies();
} catch (MsgRegistryException e) {
throw new EbxmlRegistryException(e);
}
}
/**
* Loads the access control policies from the file system folder
*

View file

@ -19,17 +19,15 @@
**/
package com.raytheon.uf.edex.registry.acp.xacml;
import java.util.List;
import org.opensaml.xacml.XACMLObject;
import org.opensaml.xacml.ctx.DecisionType.DECISION;
import org.opensaml.xacml.ctx.RequestType;
import org.opensaml.xacml.ctx.ResponseType;
import org.opensaml.xacml.ctx.StatusCodeType;
import org.opensaml.xacml.policy.ObligationType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.raytheon.uf.common.util.CollectionUtil;
import com.raytheon.uf.edex.registry.acp.xacml.engine.policy.Evaluator;
import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLProcessingException;
import com.raytheon.uf.edex.registry.acp.xacml.objects.Match;
@ -52,6 +50,7 @@ import com.raytheon.uf.edex.registry.acp.xacml.util.XACMLObjectUtil;
* ------------ ---------- ----------- --------------------------
* 8/17/2012 724 bphillip Initial Coding
* 3/18/2013 1802 bphillip Modified to use transaction boundaries and spring injection
* 7/10/2014 1717 bphillip Removed unneccessary methods
* </pre>
*
* @author bphillip
@ -61,15 +60,6 @@ import com.raytheon.uf.edex.registry.acp.xacml.util.XACMLObjectUtil;
@Transactional
public class XACMLPolicyDecisionPoint {
/** The obligations to evaluate */
private List<ObligationType> obligations;
/** The Policy or Policy Set object being used to evaluate the request */
private XACMLObject policyObject;
/** The Request being evaluated */
private RequestType request;
public XACMLPolicyDecisionPoint() {
}
@ -82,10 +72,7 @@ public class XACMLPolicyDecisionPoint {
* @param request
* The request being evaluated
*/
public XACMLPolicyDecisionPoint(XACMLObject policyObject,
RequestType request) {
this.policyObject = policyObject;
this.request = request;
public XACMLPolicyDecisionPoint(XACMLObject policyObject) {
}
/**
@ -93,63 +80,25 @@ public class XACMLPolicyDecisionPoint {
*
* @return The response
*/
public ResponseType evaluate() {
public ResponseType evaluate(XACMLObject policy, RequestType request) {
ResponseType response = null;
Match match;
try {
match = Evaluator.getInstance().evaluate(policyObject, request);
match = Evaluator.getInstance().evaluate(policy, request);
} catch (XACMLProcessingException e) {
return XACMLObjectUtil.buildResponse(DECISION.Deny,
response = XACMLObjectUtil.buildResponse(DECISION.Deny,
StatusCodeType.SC_PROCESSING_ERROR,
e.getLocalizedMessage(), "");
return response;
}
this.obligations = match.getObligations();
return XACMLObjectUtil.buildResponse(match.getMatch(),
response = XACMLObjectUtil.buildResponse(match.getMatch(),
match.getStatusCode(), match.getMessage(), "");
}
/**
* @return the obligations
*/
public List<ObligationType> getObligations() {
return obligations;
}
/**
* @param obligations
* the obligations to set
*/
public void setObligations(List<ObligationType> obligations) {
this.obligations = obligations;
}
/**
* @return the policyObject
*/
public XACMLObject getPolicyObject() {
return policyObject;
}
/**
* @param policyObject
* the policyObject to set
*/
public void setPolicyObject(XACMLObject policyObject) {
this.policyObject = policyObject;
}
/**
* @return the request
*/
public RequestType getRequest() {
return request;
}
/**
* @param request
* the request to set
*/
public void setRequest(RequestType request) {
this.request = request;
if (!CollectionUtil.isNullOrEmpty(match.getObligations())) {
response.getResult().getObligations().getObligations()
.addAll(match.getObligations());
}
return response;
}
}

View file

@ -34,6 +34,7 @@ import org.opensaml.xacml.ctx.impl.StatusCodeTypeImplBuilder;
import org.opensaml.xacml.ctx.impl.StatusDetailTypeImplBuilder;
import org.opensaml.xacml.ctx.impl.StatusMessageTypeImplBuilder;
import org.opensaml.xacml.ctx.impl.StatusTypeImplBuilder;
import org.opensaml.xacml.policy.impl.ObligationsTypeImplBuilder;
import com.raytheon.uf.edex.registry.acp.xacml.conformance.IdentifierPrefixes;
import com.raytheon.uf.edex.registry.acp.xacml.conformance.SchemaPrefixes;
@ -50,6 +51,7 @@ import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLSyntaxException;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 8/17/2012 724 bphillip Initial Coding
* 7/10/2014 1717 bphillip Set obligations on response object
* </pre>
*
* @author bphillip
@ -168,6 +170,7 @@ public class XACMLObjectUtil {
statusObj.setStatusDetail(statusDetailObj);
}
resultObj.setStatus(statusObj);
resultObj.setObligations(new ObligationsTypeImplBuilder().buildObject());
// Return the response
return resultObj;

View file

@ -0,0 +1,289 @@
package com.raytheon.uf.edex.registry.ebxml;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.LifecycleManager;
import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.MsgRegistryException;
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.Mode;
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.RemoveObjectsRequest;
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.SubmitObjectsRequest;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.AssociationType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.InternationalStringType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ObjectRefListType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ObjectRefType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.PersonType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectListType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.SlotType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.StringValueType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.raytheon.uf.common.registry.constants.AssociationTypes;
import com.raytheon.uf.common.registry.constants.RegistryObjectTypes;
import com.raytheon.uf.common.registry.ebxml.RegistryUtil;
import com.raytheon.uf.common.security.encryption.AESEncryptor;
import com.raytheon.uf.edex.registry.ebxml.dao.PersonDao;
import com.raytheon.uf.edex.registry.ebxml.dao.RoleDao;
import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException;
import com.raytheon.uf.edex.security.SecurityConfiguration;
@Path("/registryUsers/")
@Service
@Transactional
public class RegistryUsers {
public static final String USER_SUFFIX = "_RegistryUser";
public static final String USER_SLOT_NAME = "user";
public static final String PASSWORD_SLOT_NAME = "password";
public static final String ROLE_SLOT_NAME = "role";
private PersonDao personDao;
private RoleDao roleDao;
private LifecycleManager lcm;
private SecurityConfiguration securityConfig;
private AESEncryptor encryption;
@GET
@Path("getUsers")
@Produces("text/plain")
public String getRegistryUsers() {
List<PersonType> users = personDao.getAll();
StringBuilder sb = new StringBuilder();
String name = null;
String role = null;
for (PersonType user : users) {
if (user.getId().endsWith(RegistryUsers.USER_SUFFIX)) {
name = user.getSlotValue(USER_SLOT_NAME);
role = user.getSlotValue(ROLE_SLOT_NAME);
if (role == null) {
role = "<None>";
}
sb.append(name).append(";");
sb.append(role).append(";");
}
}
return sb.toString();
}
@GET
@Path("addUser")
public String addRegistryUser(@Context
UriInfo info) throws EbxmlRegistryException, MsgRegistryException {
MultivaluedMap<String, String> params = info.getQueryParameters();
String userName = params.getFirst("userName");
String pwd = params.getFirst("pwd");
String role = params.getFirst("role");
PersonType user = new PersonType();
user.setId(userName);
user.setLid(userName);
user.setObjectType(RegistryObjectTypes.PERSON);
user.setName(new InternationalStringType("User " + userName));
user.setDescription(new InternationalStringType("User" + userName));
user.setOwner(RegistryUtil.DEFAULT_OWNER);
addUser(userName, pwd, role);
return "Successfully added user " + userName + " to registry";
}
@GET
@Path("deleteUser/{userName}")
public String deleteUser(@PathParam("userName")
String userName) throws MsgRegistryException {
PersonType user = personDao.getById(userName
+ RegistryUsers.USER_SUFFIX);
if (user != null) {
remove(user);
}
return "Deleted user [" + userName + "]";
}
@GET
@Path("changePassword")
public String changePassword(@Context
UriInfo info) throws MsgRegistryException, EbxmlRegistryException {
MultivaluedMap<String, String> params = info.getQueryParameters();
String userName = params.getFirst("userName");
String pwd = params.getFirst("pwd");
PersonType user = personDao.getById(userName + USER_SUFFIX);
if (user == null) {
return "User [" + userName + "] does not exist";
}
((StringValueType) user.getSlotByName(PASSWORD_SLOT_NAME)
.getSlotValue()).setStringValue(encryptPassword(pwd));
submit(user);
return "Password for user [" + userName + "] successfully updated!";
}
@GET
@Path("changeRole")
public String changeRole(@Context
UriInfo info) throws MsgRegistryException {
MultivaluedMap<String, String> params = info.getQueryParameters();
String userName = params.getFirst("userName");
String role = params.getFirst("role");
PersonType user = personDao.getById(userName + USER_SUFFIX);
if (user == null) {
return "User [" + userName + "] does not exist";
}
((StringValueType) user.getSlotByName(ROLE_SLOT_NAME).getSlotValue())
.setStringValue(role);
submit(user);
return "Role for user [" + userName + "] successfully updated!";
}
public void addUser(String id, String password, String role)
throws EbxmlRegistryException, MsgRegistryException {
if (id == null) {
throw new EbxmlRegistryException("User ID cannot be null");
}
if (userExists(id)) {
throw new EbxmlRegistryException("User [" + id + "] already exists");
}
if (!roleExists(role)) {
throw new EbxmlRegistryException("Role [" + role
+ "] does not exist");
}
PersonType user = new PersonType();
user.setId(id + USER_SUFFIX);
user.setLid(user.getId());
user.setObjectType(RegistryObjectTypes.PERSON);
user.setName(new InternationalStringType("Registry User " + id));
user.setDescription(new InternationalStringType("Registry User " + id));
user.setOwner(RegistryUtil.DEFAULT_OWNER);
AssociationType association = new AssociationType();
association.setId(id + "_" + role + "_Association");
association.setLid(association.getId());
association.setObjectType(RegistryObjectTypes.ASSOCIATION);
association.setOwner(RegistryUtil.DEFAULT_OWNER);
association.setName(new InternationalStringType(role
+ " role assocation for user " + id));
association.setDescription(new InternationalStringType(role
+ " role assocation for user " + id));
association.setSourceObject(id);
association.setTargetObject(role);
association.setType(AssociationTypes.HAS_ROLE);
SlotType userSlot = new SlotType(USER_SLOT_NAME,
new StringValueType(id));
SlotType passwordSlot = new SlotType(PASSWORD_SLOT_NAME,
new StringValueType(encryptPassword(password)));
SlotType roleSlot = new SlotType(ROLE_SLOT_NAME, new StringValueType(
role));
user.getSlot().add(userSlot);
user.getSlot().add(passwordSlot);
user.getSlot().add(roleSlot);
submit(association, user);
}
private void remove(RegistryObjectType... objs) throws MsgRegistryException {
ObjectRefListType refList = new ObjectRefListType();
for (RegistryObjectType obj : objs) {
refList.getObjectRef().add(new ObjectRefType(obj.getId()));
}
RemoveObjectsRequest req = new RemoveObjectsRequest();
req.setId("Removing registry users");
req.setComment("Remove request to remove registry users");
req.setDeleteChildren(true);
req.setObjectRefList(refList);
lcm.removeObjects(req);
}
private void submit(RegistryObjectType... objs) throws MsgRegistryException {
SubmitObjectsRequest submitObjectsRequest = new SubmitObjectsRequest();
submitObjectsRequest.setCheckReferences(false);
submitObjectsRequest.setComment("Modifying registry user");
submitObjectsRequest.setId("Submit User objects");
submitObjectsRequest.setMode(Mode.CREATE_OR_REPLACE);
submitObjectsRequest.setUsername(RegistryUtil.registryUser);
submitObjectsRequest
.setRegistryObjectList(new RegistryObjectListType());
for (RegistryObjectType obj : objs) {
submitObjectsRequest.getRegistryObjects().add(obj);
}
lcm.submitObjects(submitObjectsRequest);
}
public boolean userExists(String userId) {
return personDao.getById(userId + USER_SUFFIX) != null;
}
private boolean roleExists(String roleId) {
return roleDao.getById(roleId) != null;
}
private String encryptPassword(String password) throws EbxmlRegistryException{
try {
return encryption.encrypt(securityConfig.getEncryptionKey(), password);
} catch (Exception e) {
throw new EbxmlRegistryException("Error encrypting password",e);
}
}
/**
* @param personDao
* the personDao to set
*/
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
/**
* @param roleDao
* the roleDao to set
*/
public void setRoleDao(RoleDao roleDao) {
this.roleDao = roleDao;
}
/**
* @param lcm
* the lcm to set
*/
public void setLcm(LifecycleManager lcm) {
this.lcm = lcm;
}
/**
* @param securityConfig the securityConfig to set
*/
public void setSecurityConfig(SecurityConfiguration securityConfig) {
this.securityConfig = securityConfig;
}
/**
* @param encryption the encryption to set
*/
public void setEncryption(AESEncryptor encryption) {
this.encryption = encryption;
}
}

View file

@ -28,9 +28,11 @@ import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
import com.raytheon.uf.edex.registry.ebxml.web.security.CredentialCache;
/**
*
* Password callback class used with WS security. Currently unused.
* Password callback class used with WS security.
*
* <pre>
*
@ -39,6 +41,7 @@ import org.apache.ws.security.WSPasswordCallback;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 3, 2012 bphillip Initial creation
* 7/10/2014 1717 bphillip Get user information from CredentialCache
*
* </pre>
*
@ -59,7 +62,8 @@ public class PasswordCallback implements CallbackHandler {
for (Callback call : callbacks) {
if (call instanceof WSPasswordCallback) {
WSPasswordCallback cb = (WSPasswordCallback) call;
cb.setPassword("password");
cb.setPassword(CredentialCache.getInstance().getUserPassword(
((WSPasswordCallback) call).getIdentifier()));
}
}
}

View file

@ -67,6 +67,7 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.util.ReflectionUtil;
import com.raytheon.uf.edex.core.EDEXUtil;
import com.raytheon.uf.edex.core.props.PropertiesFactory;
import com.raytheon.uf.edex.registry.acp.xacml.XACMLPolicyAdministrator;
import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException;
import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener;
@ -93,6 +94,7 @@ import com.raytheon.uf.edex.registry.ebxml.init.RegistryInitializedListener;
* Nov 14, 2013 2552 bkowal EbxmlJaxbManager is now accessed via getInstance
* Dec 20, 2013 2636 mpduff Set initialized to true before postInitialized is called.
* Dec 04, 2013 2584 dhladky Version based EbxmlJaxbManager
* 7/10/2014 1717 bphillip Removed xacml policy admin object
* </pre>
*
* @author bphillip
@ -119,6 +121,8 @@ public class DbInit extends com.raytheon.uf.edex.database.init.DbInit implements
private ApplicationContext applicationContext;
private XACMLPolicyAdministrator xacmlPolicyAdmin;
/**
* Creates a new instance of DbInit. This constructor should only be called
* once when loaded by the Spring container.
@ -137,6 +141,7 @@ public class DbInit extends com.raytheon.uf.edex.database.init.DbInit implements
executeRegistrySql();
populateDB();
xacmlPolicyAdmin.loadAccessControlPolicies();
}
public static boolean isDbInitialized() {
@ -404,4 +409,13 @@ public class DbInit extends com.raytheon.uf.edex.database.init.DbInit implements
throws BeansException {
this.applicationContext = applicationContext;
}
/**
* @param xacmlPolicyAdmin the xacmlPolicyAdmin to set
*/
public void setXacmlPolicyAdmin(XACMLPolicyAdministrator xacmlPolicyAdmin) {
this.xacmlPolicyAdmin = xacmlPolicyAdmin;
}
}

View file

@ -64,6 +64,7 @@ import com.raytheon.uf.edex.security.SecurityConfiguration;
* 1/15/2014 2613 bphillip Removed Service cache due to unexpected behavior
* 2/19/2014 2769 bphillip Added service cache
* 6/5/2014 1712 bphillip Moved configuration out to separate class
* 7/10/2014 1717 bphillip Added authorization policy
* </pre>
*
* @author bphillip
@ -183,6 +184,7 @@ public class RegistryRESTServices {
HTTPConduit conduit = config.getHttpConduit();
conduit.setClient(serviceConfig.getHttpClientPolicy());
conduit.setTlsClientParameters(securityConfig.getTlsParams());
conduit.setAuthorization(securityConfig.getAuthPolicy());
// Create HTTP header containing the calling registry
client.header(RegistryUtil.CALLING_REGISTRY_SOAP_HEADER_NAME,

View file

@ -48,6 +48,7 @@ import com.raytheon.uf.common.util.CollectionUtil;
* ------------ ---------- ----------- --------------------------
* 9/5/2013 1538 bphillip Initial implementation
* 2/27/2014 2769 bphillip Changed verbose output to debug level
* 7/10/2014 1717 bphillip Added session
* </pre>
*
* @author bphillip
@ -66,6 +67,14 @@ public class RegistryServiceInInterceptor extends
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message message) throws Fault {
/*
* Request the current session so that login credentials can be
* maintained across multiple calls
*/
HttpServletRequest req = (HttpServletRequest) message
.get("HTTP.REQUEST");
req.getSession(true);
if (statusHandler.isPriorityEnabled(Priority.DEBUG)) {
StringBuilder logMessage = new StringBuilder();
HttpServletRequest request = (HttpServletRequest) message

View file

@ -71,6 +71,7 @@ import com.raytheon.uf.edex.security.SecurityConfiguration;
* 1/15/2014 2613 bphillip Eliminated service caching...again
* 2/19/2014 2769 bphillip Renamed getPort method
* 6/5/2014 1712 bphillip Moved configuration out to separate class. Added outbound interceptor
* 7/10/2014 1717 bphillip Added authorization policy
* </pre>
*
* @author bphillip
@ -308,6 +309,7 @@ public class RegistrySOAPServices {
HTTPConduit conduit = (HTTPConduit) client.getConduit();
conduit.setClient(serviceConfig.getHttpClientPolicy());
conduit.setTlsClientParameters(securityConfig.getTlsParams());
conduit.setAuthorization(securityConfig.getAuthPolicy());
// Create HTTP header containing the calling registry
Map<String, List<String>> headers = new HashMap<String, List<String>>();

View file

@ -19,7 +19,6 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.edex.auth.req.AbstractPrivilegedRequestHandler;
import com.raytheon.uf.edex.auth.resp.AuthorizationResponse;
import com.raytheon.uf.edex.registry.acp.xacml.XACMLPolicyEnforcementPoint;
/**
*
@ -57,8 +56,6 @@ public class EDEXRegistryManager extends
@VisibleForTesting
static final String CAN_ONLY_STORE_SINGLE_OBJECT = "Only one object can be stored at a time, ignoring all but the first item in the list!";
private XACMLPolicyEnforcementPoint xacmlPep;
private RegistryHandler registryHandler;
/**
@ -123,11 +120,7 @@ public class EDEXRegistryManager extends
@Transactional
public AuthorizationResponse authorized(IUser user,
IRegistryRequest<?> request) throws AuthorizationException {
return xacmlPep.handleRegistryRequest(user, request);
}
public void setXacmlPep(XACMLPolicyEnforcementPoint xacmlPep) {
this.xacmlPep = xacmlPep;
return new AuthorizationResponse(true);
}
public void setRegistryHandler(RegistryHandler registryHandler) {

View file

@ -55,6 +55,7 @@ public class RegistryWebServer implements RegistryInitializedListener {
/** The jetty server instance */
private final Server jettyServer;
/**
* Creates a new Jetty Server with the given configuration file
*
@ -63,22 +64,19 @@ public class RegistryWebServer implements RegistryInitializedListener {
* @throws Exception
* If errors occur while configuring the Jetty Server
*/
public RegistryWebServer(String jettyConfigFile, SecurityConfiguration securityConfiguration) throws Exception {
public RegistryWebServer(String jettyConfigFile,
SecurityConfiguration securityConfiguration) throws Exception {
try {
statusHandler.info("Configuring registry web server from file ["
+ jettyConfigFile + "]");
FileInputStream fis = null;
try {
// Temporarily add the security properties to the java properties so it can be configured properly
System.getProperties().putAll(securityConfiguration.getSecurityProperties());
System.getProperties().putAll(
securityConfiguration.getSecurityProperties());
fis = new FileInputStream(jettyConfigFile);
XmlConfiguration configuration = new XmlConfiguration(fis);
jettyServer = (Server) configuration.configure();
} finally {
// Remove the security properties from the environment
for(Object property: securityConfiguration.getSecurityProperties().keySet()){
System.getProperties().remove(property);
}
if (fis != null) {
fis.close();
}

View file

@ -0,0 +1,300 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.edex.registry.ebxml.web.security;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.xml.ws.WebServiceException;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.PersonType;
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.eventbus.Subscribe;
import com.raytheon.uf.common.registry.constants.RegistryObjectTypes;
import com.raytheon.uf.common.registry.handler.RegistryHandlerException;
import com.raytheon.uf.common.registry.services.RegistryServiceException;
import com.raytheon.uf.common.security.encryption.AESEncryptor;
import com.raytheon.uf.edex.registry.ebxml.RegistryUsers;
import com.raytheon.uf.edex.registry.ebxml.dao.PersonDao;
import com.raytheon.uf.edex.registry.ebxml.services.RegistryRESTServices;
import com.raytheon.uf.edex.registry.events.CreateAuditTrailEvent;
import com.raytheon.uf.edex.security.SecurityConfiguration;
/**
*
* Cache object for holding users' credentials for accessing registry web
* services
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 7/10/2014 1717 bphillip Initial creation
* </pre>
*
* @author bphillip
* @version 1
**/
public class CredentialCache {
/** The singleton instance */
private static CredentialCache instance = new CredentialCache();
/** The registry REST services */
private RegistryRESTServices restServices;
/** Data access object for person type */
private PersonDao personDao;
/** The Hibernate Transaction template */
private TransactionTemplate txTemplate;
/** The security configuration */
private SecurityConfiguration securityConfig;
/** AESEncryptor object */
private AESEncryptor encryption;
/** Field denoting if this registry is running in centralRegistry mode */
public static final boolean centralRegistry = System.getProperty(
"edex.run.mode").equals("centralRegistry");
/** Address of the central registry */
private static final String CENTRAL_REGISTRY_ADDRESS = "https://"
+ (System.getProperty("ncf.host")) + ":"
+ (System.getProperty("ebxml.registry.webserver.port"));
/** Cache holding users' credentials */
private LoadingCache<String, String[]> credentialCache = CacheBuilder
.newBuilder().maximumSize(1000)
.expireAfterAccess(60, TimeUnit.MINUTES)
.build(new CacheLoader<String, String[]>() {
@Override
public String[] load(final String userName)
throws RegistryHandlerException {
return txTemplate
.execute(new TransactionCallback<String[]>() {
@Override
public String[] doInTransaction(
TransactionStatus status) {
PersonType user = null;
/*
* If we are the central registry, directly
* query the registry
*/
if (centralRegistry) {
user = personDao.getById(userName
+ RegistryUsers.USER_SUFFIX);
}
/*
* If we are not the central registry, query
* the central registry to get the user's
* information
*/
else {
try {
user = restServices
.getRegistryObject(
CENTRAL_REGISTRY_ADDRESS,
userName
+ RegistryUsers.USER_SUFFIX);
} catch (Exception e) {
throw new WebServiceException(
"Error contacting central registry!",
e);
}
}
/*
* User not found means unauthorized
*/
if (user == null) {
throw new WebServiceException("User ["
+ userName + " Not authorized!");
}
/*
* Put the user name, password, and role in
* the return array. Decrypt the password.
*/
String userName = user
.getSlotValue(RegistryUsers.USER_SLOT_NAME);
String password = null;
try {
password = encryption.decrypt(
securityConfig
.getEncryptionKey(),
(String) user
.getSlotValue(RegistryUsers.PASSWORD_SLOT_NAME));
} catch (Exception e) {
throw new RegistryServiceException(
"Error decrypting password!", e);
}
String role = user
.getSlotValue(RegistryUsers.ROLE_SLOT_NAME);
return new String[] { userName, password,
role };
}
});
}
});
/**
* Protected constructor
*/
protected CredentialCache() {
}
/**
* Gets the singleton instance of the Credential cache
*
* @return The singleton instance
*/
public static CredentialCache getInstance() {
return instance;
}
/**
* Listens for updates to users and invalidates their entries in the cache
* if they have changed
*
* @param event
* The event to examine
*/
@Subscribe
@Transactional(propagation = Propagation.REQUIRED)
public void processEvent(CreateAuditTrailEvent event) {
List<RegistryObjectType> objsAffected = event.getObjectsAffected();
for (RegistryObjectType affectedObj : objsAffected) {
if (RegistryObjectTypes.PERSON.equals(affectedObj.getObjectType())) {
credentialCache.invalidate(affectedObj.getId());
}
}
}
/**
* Gets a user from the provided user name
*
* @param userName
* The user name of the user
* @return An array containing the user name, password, and role of the user
* @throws RegistryServiceException
* If errors occur while accessing the cache
*/
public String[] getUser(String userName) throws RegistryServiceException {
try {
return credentialCache.get(userName);
} catch (ExecutionException e) {
throw new RegistryServiceException("Error retrieving user "
+ userName);
}
}
/**
* Gets the role of the given user
*
* @param userName
* The user name to get the role for
* @return The role of the given user
* @throws RegistryServiceException
* If errors occur while accessing the cache
*/
public String getUserRole(String userName) throws RegistryServiceException {
try {
return credentialCache.get(userName)[0];
} catch (ExecutionException e) {
throw new RegistryServiceException(
"Error retrieving role for user " + userName);
}
}
/**
* Gets the password for the given user
*
* @param userName
* The user to get the password for
* @return The password for the given user
* @throws RegistryServiceException
* If errors occur while accessing the cache
*/
public String getUserPassword(String userName)
throws RegistryServiceException {
try {
return credentialCache.get(userName)[1];
} catch (ExecutionException e) {
throw new RegistryServiceException(
"Error retrieving password for user " + userName);
}
}
/**
* @param restServices
* the restServices to set
*/
public void setRestServices(RegistryRESTServices restServices) {
this.restServices = restServices;
}
/**
* @param personDao
* the personDao to set
*/
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
/**
* @param txTemplate
* the txTemplate to set
*/
public void setTxTemplate(TransactionTemplate txTemplate) {
this.txTemplate = txTemplate;
}
/**
* @param securityConfig
* the securityConfig to set
*/
public void setSecurityConfig(SecurityConfiguration securityConfig) {
this.securityConfig = securityConfig;
}
/**
* @param encryption
* the encryption to set
*/
public void setEncryption(AESEncryptor encryption) {
this.encryption = encryption;
}
}

View file

@ -0,0 +1,80 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.edex.registry.ebxml.web.security;
import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.WebServiceException;
import org.eclipse.jetty.plus.jaas.spi.AbstractLoginModule;
import org.eclipse.jetty.plus.jaas.spi.UserInfo;
import org.eclipse.jetty.util.security.Credential;
import org.eclipse.jetty.util.security.Password;
import com.raytheon.uf.common.registry.services.RegistryServiceException;
/**
*
* The registry login module used by the Jetty server hosting the registry services
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 7/10/2014 1717 bphillip Initial creation
* </pre>
*
* @author bphillip
* @version 1
**/
public class RegistryLoginModule extends AbstractLoginModule {
/**
* Creates a new RegistryLoginModule
*/
public RegistryLoginModule() {
super();
}
@Override
public UserInfo getUserInfo(final String userName) {
String[] user = null;
try {
user = CredentialCache.getInstance().getUser(userName);
} catch (RegistryServiceException e) {
throw new WebServiceException("User [" + userName
+ " Not authorized!",e);
}
for(String userField:user){
if(userField == null){
throw new WebServiceException("User [" + userName
+ " Not authorized!");
}
}
List<String> roleList = new ArrayList<String>(1);
roleList.add(user[2]);
Credential credential = new Password(user[1]);
UserInfo userInfo = new UserInfo(userName, credential, roleList);
return userInfo;
}
}

View file

@ -0,0 +1,89 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.edex.registry.ebxml.web.security;
import java.io.IOException;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import com.raytheon.uf.common.security.encryption.AESEncryptor;
import com.raytheon.uf.edex.security.SecurityConfiguration;
/**
*
* Custom SslContextFacotry implementation which accepts encrypted values for passwords
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 7/10/2014 1717 bphillip Initial creation
* </pre>
*
* @author bphillip
* @version 1
**/
public class RegistrySSLContextFactory extends SslContextFactory {
private AESEncryptor encryption;
private SecurityConfiguration securityConfiguration;
public RegistrySSLContextFactory() throws IOException {
super();
this.securityConfiguration = new SecurityConfiguration();
this.encryption = new AESEncryptor();
}
@Override
public void setKeyStorePassword(String password) {
try {
super.setKeyStorePassword(encryption.decrypt(this.securityConfiguration.getEncryptionKey(),
password));
} catch (Exception e) {
throw new RuntimeException("Error setting web server properties!",
e);
}
}
@Override
public void setTrustStorePassword(String password) {
try {
super.setTrustStorePassword(encryption.decrypt(this.securityConfiguration.getEncryptionKey(),
password));
} catch (Exception e) {
throw new RuntimeException("Error setting web server properties!",
e);
}
}
public void setKeyManagerPassword(String password) {
try {
super.setKeyManagerPassword(encryption.decrypt(this.securityConfiguration.getEncryptionKey(),
password));
} catch (Exception e) {
throw new RuntimeException("Error setting web server properties!",
e);
}
}
}

View file

@ -54,9 +54,33 @@
DataType="http://www.w3.org/2001/XMLSchema#string" />
</ActionMatch>
</Action>
<Action>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">execute</AttributeValue>
<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string" />
</ActionMatch>
</Action>
<Action>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">GET</AttributeValue>
<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string" />
</ActionMatch>
</Action>
<Action>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">POST</AttributeValue>
<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string" />
</ActionMatch>
</Action>
</Actions>
</Target>
<Rule RuleId="urn:oasis:names:tc:xacml:2.0:conformance-test:IIA008:rule"
<Rule RuleId="urn:oasis:names:tc:xacml:2.0:data-delivery:default-noop-rule"
Effect="Permit">
<Description>
Default access control policy for accessing registry

View file

@ -12,6 +12,49 @@
version="2.4">
<display-name>Data Delivery Web Services</display-name>
<security-role>
<role-name>RegistryAdministrator</role-name>
</security-role>
<security-role>
<role-name>RegistryLocalAdministrator</role-name>
</security-role>
<security-role>
<role-name>RegistryUser</role-name>
</security-role>
<security-role>
<role-name>RegistryGuest</role-name>
</security-role>
<!-- Restrict user administration to only the registry admin -->
<security-constraint>
<web-resource-collection>
<web-resource-name>
Registry User Admin pages
</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>RegistryLocalAdministrator</role-name>
<role-name>RegistryAdministrator</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>
Registry User Admin pages
</web-resource-name>
<url-pattern>/registry/services/users/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>RegistryAdministrator</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>RegistryRealm</realm-name>
</login-config>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>registryEbxml</param-value>

View file

@ -26,7 +26,7 @@
<New
class="com.raytheon.uf.edex.registry.ebxml.web.security.SslNetworkTrafficSelectChannelConnector">
<Arg>
<New class="org.eclipse.jetty.http.ssl.SslContextFactory">
<New class="com.raytheon.uf.edex.registry.ebxml.web.security.RegistrySSLContextFactory">
<Set name="keyStore">
<SystemProperty name="edex.security.keystore.path" />
</Set>
@ -63,9 +63,19 @@
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<New class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="securityHandler">
<New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
<Set name="loginService">
<New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
<Set name="name"><SystemProperty name="edex.security.auth.loginService.name" /></Set>
<Set name="loginModuleName"><SystemProperty name="edex.security.auth.loginService.realm" /></Set>
</New>
</Set>
</New>
</Set>
<Set name="descriptor">WEB-INF/web.xml</Set>
<Set name="resourceBase">
<SystemProperty name="ebxml.registry.webserver.home" />
<SystemProperty name="ebxml.registry.webserver.home" />
</Set>
<Set name="contextPath">/</Set>
<Set name="parentLoaderPriority">true</Set>

View file

@ -61,6 +61,8 @@ Date Ticket# Engineer Description
<a href="/RegistrySubscriptionBackup.html" target="actionFrame">Subscription Backup</a>
<br>
<a href="/registry/federation/status.html" target="actionFrame">Federation Status</a>
<br>
<a href="/registry/services/users/defineUsers.html" target="actionFrame">User Admin</a>
</body>

View file

@ -0,0 +1,180 @@
<html>
<head>
<style type="text/css">
a {font-weight:bold;}
td {width:175px;}
button {width:190px;}
input{width:200px;}
select {width:200px;}
body { font-family: Helvetica;
margin-left: 75px;
margin-right: 75px;
background: #D3D3D3;}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<script type="text/javascript" src='/registry/registryUtil.js'></script>
<script type="text/javascript" src='/registry/services/query/queryUtil.js'></script>
<script type="text/javascript" src='/dataDeliveryUtil.js'></script>
<title>Registry User Administration</title>
</head>
<body onload="refreshUserTable()">
<h2>Registry User Administration</h2>
<h3>Add User</h3>
<table>
<tr>
<td>User ID:</td>
<td><input id="userIdInput" type="text"></input></td>
</tr>
<tr>
<td>Password:</td>
<td><input id="passwordInput" type="password"></input></td>
</tr>
<tr>
<td>Role:</td>
<td>
<select id="roleSelect">
<option value="RegistryAdministrator">RegistryAdministrator</option>
<option value="RegistryLocalAdministrator">RegistryLocalAdministrator</option>
<option value="RegistryUser">RegistryUser</option>
<option value="RegistryGuest">RegistryGuest</option>
</select></td>
</tr>
<tr>
<td/>
<td><button type="button" style='width:120px' onclick="addUser()">Add User</button></td>
</tr>
</table>
<p><p>
<hr align="left" width="500"/>
<h3>Update User</h3>
<table>
<tr>
<td>User ID:</td>
<td><select id="modifyUserSelect"/></input></td>
</tr>
<tr>
<td>Password:</td>
<td><input id="modifyPasswordInput" type="text"></input></td>
</tr>
<tr>
<td>Role:</td>
<td>
<select id="modifyRoleSelect">
<option value="RegistryAdministrator">RegistryAdministrator</option>
<option value="RegistryLocalAdministrator">RegistryLocalAdministrator</option>
<option value="RegistryUser">RegistryUser</option>
<option value="RegistryGuest">RegistryGuest</option>
</select></td>
</tr>
<tr>
<td><button type="button" style='width:120px' onclick="updatePassword()">Update Password</button></td>
<td><button type="button" style='width:120px' onclick="updateRole()">Update Role</button></td>
</tr>
</table>
<p><p>
<hr align="left" width="500"/>
<h3>Delete User</h3>
<table>
<tr>
<td>User ID:</td>
<td><select id="deleteUserSelect"/></input></td>
</tr>
<tr>
<td/>
<td><button type="button" style='width:120px' onclick="deleteUser()">Delete User</button></td>
</tr>
</table>
<p><p>
<hr align="left" width="500"/>
<p><p>
<h3>Current Users</h3>
<span id="userTableSpan"/>
</body>
<script language="JavaScript">
function refreshUserTable(){
clearComboBox("modifyUserSelect")
clearComboBox("deleteUserSelect")
var users = callRestService("rest/registryUsers/getUsers").split(";")
var usersHTML = "<table border='1'><tr><th style='width:100px;'>User ID</th><th>Role</th></tr>"
for(var i = 0; i < users.length-1;i+=2){
addOptionToList("modifyUserSelect",users[i],users[i])
addOptionToList("deleteUserSelect",users[i],users[i])
usersHTML+="<tr>"
usersHTML+="<td style='width:30px;'>"+users[i]+"</td>"
usersHTML+="<td>"+users[i+1]+"</td>"
usersHTML+="</tr>"
}
usersHTML+="</table>";
document.getElementById("userTableSpan").innerHTML=usersHTML
}
function addUser(){
var elem = document.getElementById("roleSelect")
var idx = elem.selectedIndex;
var selectedRole=elem.options[elem.selectedIndex].value
var url = "rest/registryUsers/addUser?"
url += "userName="+document.getElementById("userIdInput").value
url += "&pwd="+document.getElementById("passwordInput").value
url += "&role="+selectedRole
if(confirm("Add user "+document.getElementById("userIdInput").value+"?")){
var response = callRestService(url)
refreshUserTable()
alert(response)
}
}
function updatePassword(){
var userToModify = document.getElementById("modifyUserSelect").value
var newPass = document.getElementById("modifyPasswordInput").value
var url = "rest/registryUsers/changePassword?"
url+="userName="+userToModify
url+="&pwd="+newPass
if(confirm("Update password for user "+userToModify+"?")){
var response = callRestService(url)
refreshUserTable()
alert(response)
}
}
function updateRole(){
var userToModify = document.getElementById("modifyUserSelect").value
var newRole =document.getElementById("modifyRoleSelect").value
var url = "rest/registryUsers/changeRole?"
url+="userName="+userToModify
url+="&role="+newRole
if(confirm("Update role for user "+userToModify+"?")){
var response = callRestService(url)
refreshUserTable()
alert(response)
}
}
function deleteUser(){
var userToDelete = getSelectedComboValue("deleteUserSelect")
if(confirm("Delete user "+userToDelete+"?")){
var response = callRestService("rest/registryUsers/deleteUser/"+userToDelete)
refreshUserTable()
alert(response)
}
}
</script>
</html>

View file

@ -19,7 +19,7 @@
http://cxf.apache.org/configuration/security
http://cxf.apache.org/schemas/configuration/security.xsd">
<context:property-placeholder />
<context:property-placeholder/>
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
@ -65,6 +65,8 @@
<jaxws:server id="QueryService" address="/queryManager">
<jaxws:inInterceptors>
<ref bean="webServiceInInterceptor" />
<ref bean="authenticationInterceptor" />
<ref bean="xacmlInterceptor" />
</jaxws:inInterceptors>
<jaxws:serviceBean>
<ref bean="QueryServiceWrapper" />
@ -74,6 +76,8 @@
<jaxws:server id="NotificationListenerService" address="/notificationListener">
<jaxws:inInterceptors>
<ref bean="webServiceInInterceptor" />
<ref bean="authenticationInterceptor" />
<ref bean="xacmlInterceptor" />
</jaxws:inInterceptors>
<jaxws:serviceBean>
<ref bean="NotificationListenerServiceWrapper" />
@ -83,6 +87,8 @@
<jaxws:server id="LifecycleManagerService" address="/lifecycleManager">
<jaxws:inInterceptors>
<ref bean="webServiceInInterceptor" />
<ref bean="authenticationInterceptor" />
<ref bean="xacmlInterceptor" />
</jaxws:inInterceptors>
<jaxws:serviceBean>
<ref bean="LifecycleManagerServiceWrapper" />
@ -92,6 +98,8 @@
<jaxws:server id="ValidatorService" address="/validator">
<jaxws:inInterceptors>
<ref bean="webServiceInInterceptor" />
<ref bean="authenticationInterceptor" />
<ref bean="xacmlInterceptor" />
</jaxws:inInterceptors>
<jaxws:serviceBean>
<ref bean="ValidatorServiceWrapper" />
@ -101,6 +109,8 @@
<jaxws:server id="CatalogerService" address="/cataloger">
<jaxws:inInterceptors>
<ref bean="webServiceInInterceptor" />
<ref bean="authenticationInterceptor" />
<ref bean="xacmlInterceptor" />
</jaxws:inInterceptors>
<jaxws:serviceBean>
<ref bean="catalogerServiceImpl" />
@ -112,11 +122,14 @@
<jaxrs:server id="registryRestServices" address="/rest">
<jaxrs:inInterceptors>
<ref bean="webServiceInInterceptor" />
<ref bean="authenticationInterceptor" />
<ref bean="xacmlInterceptor" />
</jaxrs:inInterceptors>
<jaxrs:serviceBeans>
<ref bean="registryObjectsRestService" />
<ref bean="repositoryObjectsRestService" />
<ref bean="queryProtocolRestService" />
<ref bean="registryUsers" />
</jaxrs:serviceBeans>
</jaxrs:server>
<!-- End REST Endpoint definitions -->

View file

@ -17,8 +17,6 @@
[Enter License Description here.]
</license>
<import feature="com.raytheon.uf.edex.registry.client.feature" version="1.0.0.qualifier"/>
<plugin
id="com.raytheon.uf.common.registry.schemas.iso19115"
download-size="0"
@ -33,4 +31,11 @@
version="0.0.0"
unpack="false"/>
<plugin
id="com.raytheon.uf.common.security"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

View file

@ -9,5 +9,7 @@ Require-Bundle: org.eclipse.jetty;bundle-version="7.6.14",
com.raytheon.uf.edex.core;bundle-version="1.14.0",
com.raytheon.uf.common.util;bundle-version="1.14.0",
com.raytheon.uf.common.status;bundle-version="1.12.1174",
org.apache.commons.cxf;bundle-version="2.7.11"
org.apache.commons.cxf;bundle-version="2.7.11",
com.raytheon.uf.common.security;bundle-version="1.14.0",
org.apache.ws.security;bundle-version="1.0.0"
Export-Package: com.raytheon.uf.edex.security

View file

@ -7,7 +7,8 @@
<bean id="securityConfiguration" class="com.raytheon.uf.edex.security.SecurityConfiguration" />
<bean id="encryptedPropertyLoader" class="com.raytheon.uf.edex.security.EncryptedProperties">
<constructor-arg value="/awips2/edex/conf/security/security.properties"/>
<constructor-arg
value="/awips2/edex/conf/resources/site/${AW_SITE_IDENTIFIER}/security.properties" />
</bean>
</beans>

View file

@ -25,12 +25,14 @@ import java.util.Properties;
import org.eclipse.jetty.util.security.Password;
import com.raytheon.uf.common.security.encryption.AESEncryptor;
/**
*
* Class used with the WSS4j interceptors. This class extends the java
* Properties class to allow obfuscated properties to be contained in the
* properties file. The properties may be obfuscated using Jetty's obfuscation
* methods.
* Properties class to allow obfuscated and encrypted password properties to be contained in the
* properties file. The password properties may be obfuscated using Jetty's obfuscation
* method or may be encrypted using the com.raytheon.uf.common.security.encryption.AESEncryptor class
*
* <pre>
*
@ -39,46 +41,56 @@ import org.eclipse.jetty.util.security.Password;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 6/5/2014 1712 bphillip Initial Creation
* 7/10/2014 1717 bphillip Added support for additional encryption
* </pre>
*
* @author bphillip
* @version 1
* @see org.eclipse.jetty.util.security.Password.obfuscate(String)
* @see org.eclipse.jetty.util.security.Password.deobfuscate(String)
**/
public class EncryptedProperties extends Properties {
private static final long serialVersionUID = -8799654229761166379L;
private static final long serialVersionUID = -8799654229761166379L;
/** The prefix prepended to an obfuscated property */
private static final String OBFUSCATED_PREFIX = "OBF:";
private AESEncryptor encryption;
/**
* Creates a new EncryptedProperties object
*
* @param filename
* The file containing the properties
* @throws IOException
* If errors occur while reading the properties file
*/
public EncryptedProperties(String filename) throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(filename);
load(fis);
} finally {
if (fis != null) {
fis.close();
}
}
}
/**
* Creates a new EncryptedProperties object
*
* @param filename
* The file containing the properties
* @throws IOException
* If errors occur while reading the properties file
*/
public EncryptedProperties(String filename) throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(filename);
load(fis);
} finally {
if (fis != null) {
fis.close();
}
}
encryption = new AESEncryptor();
}
public String getProperty(String propertyName){
String property = super.getProperty(propertyName);
if (property != null
&& property.startsWith(OBFUSCATED_PREFIX)) {
return Password.deobfuscate(property);
}
return property;
}
public String getProperty(String propertyName) {
String property = super.getProperty(propertyName);
if (property != null) {
if (property.startsWith("OBF:")) {
return Password.deobfuscate(property);
} else if (propertyName.contains("password")) {
try {
return encryption.decrypt(
getProperty("edex.security.encryption.key"),
property);
} catch (Exception e) {
throw new RuntimeException(
"Error decrypting password property "
+ propertyName, e);
}
}
}
return property;
}
}

View file

@ -28,9 +28,8 @@ import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.edex.core.modes.EDEXModesUtil;
/**
@ -44,6 +43,7 @@ import com.raytheon.uf.edex.core.modes.EDEXModesUtil;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 6/5/2014 1712 bphillip Initial Creation
* 7/10/2014 1717 bphillip Added authorization policy
* </pre>
*
* @author bphillip
@ -51,141 +51,169 @@ import com.raytheon.uf.edex.core.modes.EDEXModesUtil;
**/
public class SecurityConfiguration {
/** The logger instance */
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(SecurityConfiguration.class);
/** The directory containing security related files such as keystores */
private static final String SECURITY_DIR = EDEXModesUtil.CONF_DIR
+ File.separator + "resources/site" + File.separator
+ System.getenv("AW_SITE_IDENTIFIER") + File.separator;
/** The directory containing security related files such as keystores */
private static final String SECURITY_DIR = EDEXModesUtil.CONF_DIR
+ File.separator + "security" + File.separator;
/** The properties file containing the security configuration items */
private static final String SECURITY_PROPERTIES_FILE = SECURITY_DIR
+ "security.properties";
/** The properties file containing the security configuration items */
private static final String SECURITY_PROPERTIES_FILE = SECURITY_DIR
+ "security.properties";
/** Properties object for the security configuration */
private EncryptedProperties securityProperties;
/** Properties object for the security configuration */
private EncryptedProperties securityProperties;
/** The https configuration */
private TLSClientParameters tlsParams;
/** The https configuration */
private TLSClientParameters tlsParams;
/** The authorization policy */
private AuthorizationPolicy authPolicy;
/** Keystore factory */
private KeyManagerFactory kmf;
/** Keystore factory */
private KeyManagerFactory kmf;
/** Trust store factory */
private TrustManagerFactory tmf;
/** Trust store factory */
private TrustManagerFactory tmf;
/**
* Creates and initializes a new Security configuration object based on the
* security properties specified
* @throws IOException
*/
public SecurityConfiguration() throws IOException {
securityProperties = new EncryptedProperties(SECURITY_PROPERTIES_FILE);
initKeyStore();
initTrustStore();
initTLSParams();
}
/**
* Creates and initializes a new Security configuration object based on the
* security properties specified
*
* @throws IOException
*/
public SecurityConfiguration() throws IOException {
securityProperties = new EncryptedProperties(SECURITY_PROPERTIES_FILE);
initKeyStore();
initTrustStore();
initTLSParams();
initAuthPolicy();
}
/**
* Initializes the TLS parameters
*/
private void initTLSParams() {
tlsParams = new TLSClientParameters();
tlsParams.setKeyManagers(kmf.getKeyManagers());
tlsParams.setTrustManagers(tmf.getTrustManagers());
tlsParams.setDisableCNCheck(Boolean
.parseBoolean(getProperty("edex.security.disableCNCheck")));
}
/**
* Initializes the authorization policy
*/
private void initAuthPolicy() {
authPolicy = new AuthorizationPolicy();
String user = getProperty("edex.security.auth.user");
authPolicy.setUserName(user);
authPolicy.setPassword(getProperty("edex.security.auth.password"));
authPolicy
.setAuthorizationType(getProperty("edex.security.auth.authorizationType"));
}
/**
* Initializes the keystore
*/
private void initKeyStore() {
FileInputStream fis = null;
KeyStore keystore = null;
char[] storepass = getProperty("edex.security.keystore.password").toCharArray();
/**
* Initializes the TLS parameters
*/
private void initTLSParams() {
tlsParams = new TLSClientParameters();
tlsParams.setKeyManagers(kmf.getKeyManagers());
tlsParams.setTrustManagers(tmf.getTrustManagers());
tlsParams.setDisableCNCheck(Boolean
.parseBoolean(getProperty("edex.security.disableCNCheck")));
}
try {
kmf = KeyManagerFactory
.getInstance(getProperty("edex.security.keystore.algorithm"));
fis = new FileInputStream(
getProperty("edex.security.keystore.path"));
keystore = KeyStore
.getInstance(getProperty("edex.security.keystore.type"));
keystore.load(fis, storepass);
kmf.init(keystore, storepass);
} catch (Exception e) {
throw new SecurityException("Error initializing keystore", e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(
"Error closing file input stream!", e);
}
}
}
}
/**
* Initializes the keystore
*/
private void initKeyStore() {
FileInputStream fis = null;
KeyStore keystore = null;
char[] storepass = getProperty("edex.security.keystore.password")
.toCharArray();
/**
* Initializes the trust store
*/
private void initTrustStore() {
FileInputStream fis = null;
KeyStore truststore = null;
char[] storepass = getProperty("edex.security.truststore.password").toCharArray();
try {
kmf = KeyManagerFactory
.getInstance(getProperty("edex.security.keystore.algorithm"));
fis = new FileInputStream(
getProperty("edex.security.keystore.path"));
keystore = KeyStore
.getInstance(getProperty("edex.security.keystore.type"));
keystore.load(fis, storepass);
kmf.init(keystore, storepass);
} catch (Exception e) {
throw new SecurityException("Error initializing keystore", e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(
"Error closing file input stream!", e);
}
}
}
}
try {
tmf = TrustManagerFactory
.getInstance(getProperty("edex.security.truststore.algorithm"));
fis = new FileInputStream(
getProperty("edex.security.truststore.path"));
truststore = KeyStore
.getInstance(getProperty("edex.security.truststore.type"));
truststore.load(fis, storepass);
tmf.init(truststore);
} catch (Exception e) {
throw new SecurityException("Error initializing truststore", e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(
"Error closing file input stream!", e);
}
}
}
}
/**
* Initializes the trust store
*/
private void initTrustStore() {
FileInputStream fis = null;
KeyStore truststore = null;
char[] storepass = getProperty("edex.security.truststore.password")
.toCharArray();
/**
* Gets a security property.
* @param propertyName The name of the property to get
* @return The property value
*/
private String getProperty(String propertyName) {
String prop = securityProperties.getProperty(propertyName);
if (prop == null || prop.trim().isEmpty()) {
throw new SecurityException("Required property not set: "
+ propertyName);
}
return prop;
}
try {
tmf = TrustManagerFactory
.getInstance(getProperty("edex.security.truststore.algorithm"));
fis = new FileInputStream(
getProperty("edex.security.truststore.path"));
truststore = KeyStore
.getInstance(getProperty("edex.security.truststore.type"));
truststore.load(fis, storepass);
tmf.init(truststore);
} catch (Exception e) {
throw new SecurityException("Error initializing truststore", e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(
"Error closing file input stream!", e);
}
}
}
}
/**
* Gets the TLSClientParameters
*
* @return The TLSClientParameters
*/
public TLSClientParameters getTlsParams() {
return tlsParams;
}
public String getEncryptionKey() {
return getProperty("edex.security.encryption.key");
}
public EncryptedProperties getSecurityProperties() {
return securityProperties;
}
/**
* Gets a security property.
*
* @param propertyName
* The name of the property to get
* @return The property value
*/
public String getProperty(String propertyName) {
String prop = securityProperties.getProperty(propertyName);
if (prop == null || prop.trim().isEmpty()) {
throw new SecurityException("Required property not set: "
+ propertyName);
}
return prop;
}
/**
* Gets the TLSClientParameters
*
* @return The TLSClientParameters
*/
public TLSClientParameters getTlsParams() {
return tlsParams;
}
public EncryptedProperties getSecurityProperties() {
return securityProperties;
}
/**
* @return the authPolicy
*/
public AuthorizationPolicy getAuthPolicy() {
return authPolicy;
}
}