cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject [3/4] [FEDIZ-7] - Largish refactor of Fediz code to accomadate other protocols
Date Thu, 19 Jun 2014 16:31:00 GMT
http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
new file mode 100644
index 0000000..2eae858
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/FedizContext.java
@@ -0,0 +1,397 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cxf.fediz.core.config;
+
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.cxf.fediz.core.config.jaxb.CertificateStores;
+import org.apache.cxf.fediz.core.config.jaxb.ContextConfig;
+import org.apache.cxf.fediz.core.config.jaxb.FederationProtocolType;
+import org.apache.cxf.fediz.core.config.jaxb.KeyManagersType;
+import org.apache.cxf.fediz.core.config.jaxb.KeyStoreType;
+import org.apache.cxf.fediz.core.config.jaxb.ProtocolType;
+import org.apache.cxf.fediz.core.config.jaxb.SamlProtocolType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustManagersType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuerType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuers;
+import org.apache.cxf.fediz.core.exception.IllegalConfigurationException;
+import org.apache.wss4j.common.cache.ReplayCache;
+import org.apache.wss4j.common.cache.ReplayCacheFactory;
+import org.apache.wss4j.common.crypto.CertificateStore;
+import org.apache.wss4j.common.crypto.Crypto;
+import org.apache.wss4j.common.crypto.CryptoFactory;
+import org.apache.wss4j.common.crypto.Merlin;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.Loader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FedizContext implements Closeable {
+    
+    public static final String CACHE_KEY_PREFIX = "fediz.replay.cache";
+
+    private static final Logger LOG = LoggerFactory.getLogger(FedizContext.class);
+    
+    private ContextConfig config;
+
+    private boolean detectExpiredTokens = true;
+    private boolean detectReplayedTokens = true;
+    private String relativePath;
+    private ReplayCache replayCache;
+    private Protocol protocol;
+    private List<TrustManager> certificateStores;
+    private KeyManager keyManager;
+    private KeyManager decryptionKeyManager;
+    private ClassLoader classloader;
+    
+
+    public FedizContext(ContextConfig config) {
+        this.config = config;
+        
+    }
+    
+    public void init() {
+        //get validators initialized
+        getProtocol();
+    }
+
+    public List<String> getAudienceUris() {
+        return config.getAudienceUris().getAudienceItem();
+    }
+
+    public List<TrustedIssuer> getTrustedIssuers() {
+        TrustedIssuers issuers = config.getTrustedIssuers();
+        List<TrustedIssuerType> trustManagers =  issuers.getIssuer();
+        List<TrustedIssuer> trustedIssuers = new ArrayList<TrustedIssuer>();
+        for (TrustedIssuerType manager:trustManagers) {
+            trustedIssuers.add(new TrustedIssuer(manager));
+        }
+        return trustedIssuers; 
+    }
+    
+    public List<TrustManager> getCertificateStores() {
+        if (certificateStores != null) {
+            return certificateStores;
+        }
+        certificateStores = new ArrayList<TrustManager>();
+        CertificateStores certStores = config.getCertificateStores();
+        List<TrustManagersType> trustManagers = certStores.getTrustManager();
+        for (TrustManagersType manager:trustManagers) {
+            TrustManager tm = new TrustManager(manager);
+            
+            Crypto crypto = null;
+            try {
+                if (manager.getKeyStore().getType().equalsIgnoreCase("PEM")) {
+                    X509Certificate[] certificates = new X509Certificate[1];
+                    certificates[0] = readX509Certificate(tm.getName());
+                    crypto = new CertificateStore(certificates);
+                } else {
+                    Properties sigProperties = createCryptoProperties(manager);
+                    crypto = CryptoFactory.getInstance(sigProperties);
+                }
+                tm.setCrypto(crypto);
+                certificateStores.add(tm);
+            } catch (WSSecurityException e) {
+                LOG.error("Failed to load keystore '" + tm.getName() + "'", e);
+                throw new IllegalConfigurationException("Failed to load keystore '" + tm.getName() + "'");
+            }
+        }
+        return certificateStores; 
+    }
+
+    public BigInteger getMaximumClockSkew() {
+        if (config.getMaximumClockSkew() == null) {
+            return BigInteger.valueOf(5L);
+        } else {
+            return config.getMaximumClockSkew();
+        }
+    }
+    
+    public void setMaximumClockSkew(BigInteger maximumClockSkew) {
+        config.setMaximumClockSkew(maximumClockSkew);
+    }
+
+    //    public TrustManager getServiceCertificate() {
+    //        return new TrustManager(config.getServiceCertificate());
+    //    }
+
+    public Protocol getProtocol() {
+        if (protocol != null) {
+            return protocol;
+        }
+        ProtocolType type = config.getProtocol();
+        if (type instanceof FederationProtocolType) {
+            protocol = new FederationProtocol(type);
+        } else if (type instanceof SamlProtocolType) {
+            protocol = new SAMLProtocol(type);
+        }
+        
+        if (protocol != null) {
+            protocol.setClassloader(getClassloader());
+        }
+        return protocol;
+    }
+
+    public String getLogoutURL() {
+        return config.getLogoutURL();
+    }
+
+    public String getLogoutRedirectTo() {
+        return config.getLogoutRedirectTo();
+    }
+    
+    
+    public KeyManager getSigningKey() {
+        //return new KeyManager(config.getSigningKey());
+        
+        if (keyManager != null) {
+            return keyManager;
+        }
+        keyManager = new KeyManager(config.getSigningKey());
+        Properties sigProperties = createCryptoProperties(config.getSigningKey());
+        Crypto crypto;
+        try {
+            crypto = CryptoFactory.getInstance(sigProperties);
+            keyManager.setCrypto(crypto);
+        } catch (WSSecurityException e) {
+            keyManager = null;
+            LOG.error("Failed to load keystore '" + keyManager.getName() + "'", e);
+            throw new IllegalConfigurationException("Failed to load keystore '" + keyManager.getName() + "'");
+        }
+        
+        return keyManager; 
+        
+    }
+    
+    public KeyManager getDecryptionKey() {
+        if (decryptionKeyManager != null) {
+            return decryptionKeyManager;
+        }
+        decryptionKeyManager = new KeyManager(config.getTokenDecryptionKey());
+        Properties decProperties = createCryptoProperties(config.getTokenDecryptionKey());
+        Crypto crypto;
+        try {
+            crypto = CryptoFactory.getInstance(decProperties);
+            decryptionKeyManager.setCrypto(crypto);
+        } catch (WSSecurityException e) {
+            decryptionKeyManager = null;
+            LOG.error("Failed to load keystore '" + decryptionKeyManager.getName() + "'", e);
+            throw new IllegalConfigurationException("Failed to load keystore '" + decryptionKeyManager.getName() + "'");
+        }
+        
+        return decryptionKeyManager; 
+        
+    }
+
+    public ReplayCache getTokenReplayCache() {
+        if (replayCache != null) {
+            return replayCache;
+        }
+        String replayCacheString = config.getTokenReplayCache();
+        String cacheKey = CACHE_KEY_PREFIX + "-" + config.getName();
+        ReplayCacheFactory replayCacheFactory = ReplayCacheFactory.newInstance();
+        if (replayCacheString == null || "".equals(replayCacheString)) {
+            replayCache = replayCacheFactory.newReplayCache(cacheKey, "fediz-ehcache.xml");
+        } else {
+            try {
+                Class<?> replayCacheClass = Loader.loadClass(replayCacheString);
+                replayCache = (ReplayCache) replayCacheClass.newInstance();
+            } catch (ClassNotFoundException e) {
+                replayCache = replayCacheFactory.newReplayCache(cacheKey, "fediz-ehcache.xml");
+            } catch (InstantiationException e) {
+                replayCache = replayCacheFactory.newReplayCache(cacheKey, "fediz-ehcache.xml");
+            } catch (IllegalAccessException e) {
+                replayCache = replayCacheFactory.newReplayCache(cacheKey, "fediz-ehcache.xml");
+            }
+        }
+        return replayCache;
+    }
+
+    public String getName() {
+        return config.getName();
+    }
+
+
+    public boolean isDetectExpiredTokens() {
+        return detectExpiredTokens;
+    }
+    
+    public void setDetectExpiredTokens(boolean detectExpiredTokens) {
+        this.detectExpiredTokens = detectExpiredTokens;
+    }
+
+    
+    public boolean isDetectReplayedTokens() {
+        return detectReplayedTokens;
+    }
+
+    public void setDetectReplayedTokens(boolean detectReplayedTokens) {
+        this.detectReplayedTokens = detectReplayedTokens;
+    }
+
+    public void setRelativePath(String relativePath) {
+        this.relativePath = relativePath;
+    }
+
+    public String getRelativePath() {
+        return relativePath;
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (replayCache != null) {
+            replayCache.close();
+        }
+    }
+    
+    private Properties createCryptoProperties(TrustManagersType tm) {
+        String trustStoreFile = null;
+        String trustStorePw = null;
+        KeyStoreType ks = tm.getKeyStore();
+        if (ks.getFile() != null && !ks.getFile().isEmpty()) {
+            trustStoreFile = ks.getFile();
+            trustStorePw = ks.getPassword();
+        } else {
+            throw new IllegalStateException("No certificate store configured");
+        }
+        File f = new File(trustStoreFile);
+        if (!f.exists() && getRelativePath() != null && !getRelativePath().isEmpty()) {
+            trustStoreFile = getRelativePath().concat(File.separator + trustStoreFile);
+        }
+        
+        if (trustStoreFile == null || trustStoreFile.isEmpty()) {
+            throw new IllegalConfigurationException("truststoreFile not configured");
+        }
+        if (trustStorePw == null || trustStorePw.isEmpty()) {
+            throw new IllegalConfigurationException("trustStorePw not configured");
+        }
+        Properties p = new Properties();
+        p.put("org.apache.ws.security.crypto.provider",
+                "org.apache.ws.security.components.crypto.Merlin");
+        p.put("org.apache.ws.security.crypto.merlin.keystore.type", "jks");
+        p.put("org.apache.ws.security.crypto.merlin.keystore.password",
+              trustStorePw);
+        p.put("org.apache.ws.security.crypto.merlin.keystore.file",
+              trustStoreFile);
+        return p;
+    }
+    
+    private Properties createCryptoProperties(KeyManagersType km) {
+        String keyStoreFile = null;
+        String keyStorePw = null;
+        String keyType = "jks";
+        KeyStoreType ks = km.getKeyStore();
+        if (ks.getFile() != null && !ks.getFile().isEmpty()) {
+            keyStoreFile = ks.getFile();
+            keyStorePw = ks.getPassword();
+        } else {
+            throw new IllegalStateException("No certificate store configured");
+        }
+        File f = new File(keyStoreFile);
+        if (!f.exists() && getRelativePath() != null && !getRelativePath().isEmpty()) {
+            keyStoreFile = getRelativePath().concat(File.separator + keyStoreFile);
+        }
+        
+        if (keyStoreFile == null || keyStoreFile.isEmpty()) {
+            throw new IllegalConfigurationException("truststoreFile not configured");
+        }
+        if (keyStorePw == null || keyStorePw.isEmpty()) {
+            throw new IllegalConfigurationException("trustStorePw not configured");
+        }
+        if (ks.getType() != null) {
+            keyType = ks.getType();
+        }
+        
+        Properties p = new Properties();
+        p.put("org.apache.ws.security.crypto.provider",
+                "org.apache.ws.security.components.crypto.Merlin");
+        p.put("org.apache.ws.security.crypto.merlin.keystore.type", keyType);
+        p.put("org.apache.ws.security.crypto.merlin.keystore.password",
+              keyStorePw);
+        p.put("org.apache.ws.security.crypto.merlin.keystore.file",
+              keyStoreFile);
+        return p;
+    }
+    
+    private X509Certificate readX509Certificate(String filename) {
+        Certificate cert = null;
+        BufferedInputStream bis = null;
+        try {
+            ClassLoader cl = getClassloader();
+            if (cl == null) {
+                cl = Thread.currentThread().getContextClassLoader();
+            }
+            InputStream is = Merlin.loadInputStream(cl, filename);
+            
+            bis = new BufferedInputStream(is);
+
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+            if (bis.available() > 0) {
+                cert = cf.generateCertificate(bis);
+                if (!(cert instanceof X509Certificate)) {
+                    LOG.error("Certificate " + filename + " is not of type X509Certificate");
+                    throw new IllegalConfigurationException("Certificate "
+                                                            + filename + " is not of type X509Certificate");
+                }
+                if (bis.available() > 0) {
+                    LOG.warn("There are more certificates configured in " + filename + ". Only first is parsed");
+                }
+                return (X509Certificate)cert;    
+            } else  {
+                LOG.error("No bytes can be read in certificate file " + filename);
+                throw new IllegalConfigurationException("No bytes can be read in certificate file " + filename);
+            }
+        } catch (IllegalConfigurationException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            LOG.error("Failed to read certificate file " + filename, ex);
+            throw new IllegalConfigurationException("Failed to read certificate file " + filename, ex);
+        } finally {
+            try {
+                bis.close();
+            } catch (IOException ex) {
+                LOG.error("Failed to close certificate file " + filename, ex);
+            }
+        }
+    }
+
+    public ClassLoader getClassloader() {
+        return classloader;
+    }
+
+    public void setClassloader(ClassLoader classloader) {
+        this.classloader = classloader;
+    }
+    
+    
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/Protocol.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/Protocol.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/Protocol.java
index 75577c9..1683e6e 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/Protocol.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/Protocol.java
@@ -19,10 +19,21 @@
 
 package org.apache.cxf.fediz.core.config;
 
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.cxf.fediz.core.config.jaxb.ArgumentType;
+import org.apache.cxf.fediz.core.config.jaxb.CallbackType;
 import org.apache.cxf.fediz.core.config.jaxb.ProtocolType;
+import org.apache.cxf.fediz.core.util.ClassLoaderUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public abstract class Protocol {
+    private static final Logger LOG = LoggerFactory.getLogger(Protocol.class);
+                                                              
     private ProtocolType protocolType;
+    private ClassLoader classloader;
+    private Object issuer;
 
     public Protocol(ProtocolType protocolType) {
         super();
@@ -49,6 +60,72 @@ public abstract class Protocol {
         return protocolType.toString();
     }
     
+    public ClassLoader getClassloader() {
+        return classloader;
+    }
+
+    public void setClassloader(ClassLoader classloader) {
+        this.classloader = classloader;
+    }
     
+    public String getRoleDelimiter() {
+        return getProtocolType().getRoleDelimiter();
+    }
+
+    public void setRoleDelimiter(String value) {
+        getProtocolType().setRoleDelimiter(value);
+    }
+
+    public String getRoleURI() {
+        return getProtocolType().getRoleURI();
+    }
+
+    public void setRoleURI(String value) {
+        getProtocolType().setRoleURI(value);
+    }
+
+    public Object getIssuer() {
+        if (this.issuer != null) {
+            return this.issuer;
+        }
+        CallbackType cbt = getProtocolType().getIssuer();
+        this.issuer = loadCallbackType(cbt, "Issuer");
+        return this.issuer;
+    }
+
+    public void setIssuer(Object value) {
+        final boolean isString = value instanceof String;
+        final boolean isCallbackHandler = value instanceof CallbackHandler;
+        if (isString || isCallbackHandler) {
+            this.issuer = value;
+        } else {
+            LOG.error("Unsupported 'Issuer' object");
+            throw new IllegalArgumentException("Unsupported 'Issuer' object. Type must be "
+                                               + "java.lang.String or javax.security.auth.callback.CallbackHandler.");
+        }
+    }
+    
+    protected Object loadCallbackType(CallbackType cbt, String name) {
+        if (cbt == null) {
+            return null;
+        }
+        if (cbt.getType() == null || cbt.getType().equals(ArgumentType.STRING)) {
+            return new String(cbt.getValue());
+        } else if (cbt.getType().equals(ArgumentType.CLASS)) {
+            try {
+                if (getClassloader() == null) {
+                    return ClassLoaderUtils.loadClass(cbt.getValue(), this.getClass()).newInstance();
+                } else {
+                    return getClassloader().loadClass(cbt.getValue()).newInstance();
+                }
+            } catch (Exception e) {
+                LOG.error("Failed to create instance of " + cbt.getValue(), e);
+                throw new IllegalStateException("Failed to create instance of " + cbt.getValue());
+            }            
+        } else {
+            LOG.error("Only String and Class are supported for '" + name + "'");
+            throw new IllegalStateException("Only String and Class are supported for '" + name + "'");
+        }
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/SAMLProtocol.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/SAMLProtocol.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/SAMLProtocol.java
new file mode 100644
index 0000000..b334537
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/config/SAMLProtocol.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cxf.fediz.core.config;
+
+import org.apache.cxf.fediz.core.config.jaxb.ProtocolType;
+
+public class SAMLProtocol extends Protocol {
+
+    // private static final Logger LOG = LoggerFactory.getLogger(SAMLProtocol.class);
+    
+    public SAMLProtocol(ProtocolType protocolType) {
+        super(protocolType);
+        
+        /*FederationProtocolType fp = (FederationProtocolType)protocolType;
+        if (fp.getTokenValidators() != null && fp.getTokenValidators().getValidator() != null) {
+            for (String validatorClassname : fp.getTokenValidators().getValidator()) {
+                Object obj = null;
+                try {
+                    if (super.getClassloader() == null) {
+                        obj = ClassLoaderUtils.loadClass(validatorClassname, this.getClass()).newInstance();
+                    } else {
+                        obj = super.getClassloader().loadClass(validatorClassname).newInstance();
+                    }
+                } catch (Exception ex) {
+                    LOG.error("Failed to instantiate TokenValidator implementation class: '"
+                              + validatorClassname + "'\n" + ex.getClass().getCanonicalName() + ": " + ex.getMessage());
+                }
+                if (obj instanceof TokenValidator) {
+                    validators.add((TokenValidator)obj);
+                } else if (obj != null) {
+                    LOG.error("Invalid TokenValidator implementation class: '" + validatorClassname + "'");
+                }
+            }
+        }*/
+        
+        // add SAMLTokenValidator as the last one
+        // Fediz chooses the first validator in the list if its
+        // canHandleToken or canHandleTokenType method return true
+        //SAMLTokenValidator validator = new SAMLTokenValidator();
+        //validators.add(validators.size(), validator);
+    }
+
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/metadata/MetadataWriter.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/metadata/MetadataWriter.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/metadata/MetadataWriter.java
index 9ef969c..c3c97ed 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/metadata/MetadataWriter.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/metadata/MetadataWriter.java
@@ -34,8 +34,8 @@ import javax.xml.stream.XMLStreamWriter;
 import org.w3c.dom.Document;
 
 import org.apache.cxf.fediz.core.config.Claim;
-import org.apache.cxf.fediz.core.config.FederationContext;
 import org.apache.cxf.fediz.core.config.FederationProtocol;
+import org.apache.cxf.fediz.core.config.FedizContext;
 import org.apache.cxf.fediz.core.config.Protocol;
 import org.apache.cxf.fediz.core.exception.ProcessingException;
 import org.apache.cxf.fediz.core.util.DOMUtils;
@@ -61,7 +61,7 @@ public class MetadataWriter {
     }
 
     //CHECKSTYLE:OFF
-    public Document getMetaData(FederationContext config) throws ProcessingException {
+    public Document getMetaData(FedizContext config) throws ProcessingException {
 
         try {
             ByteArrayOutputStream bout = new ByteArrayOutputStream(4096);

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
new file mode 100644
index 0000000..12f4669
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
@@ -0,0 +1,681 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cxf.fediz.core.processor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.apache.cxf.fediz.core.FederationConstants;
+import org.apache.cxf.fediz.core.TokenValidator;
+import org.apache.cxf.fediz.core.TokenValidatorRequest;
+import org.apache.cxf.fediz.core.TokenValidatorResponse;
+import org.apache.cxf.fediz.core.config.FederationProtocol;
+import org.apache.cxf.fediz.core.config.FedizContext;
+import org.apache.cxf.fediz.core.config.KeyManager;
+import org.apache.cxf.fediz.core.exception.ProcessingException;
+import org.apache.cxf.fediz.core.exception.ProcessingException.TYPE;
+import org.apache.cxf.fediz.core.metadata.MetadataWriter;
+import org.apache.cxf.fediz.core.spi.FreshnessCallback;
+import org.apache.cxf.fediz.core.spi.HomeRealmCallback;
+import org.apache.cxf.fediz.core.spi.IDPCallback;
+import org.apache.cxf.fediz.core.spi.RealmCallback;
+import org.apache.cxf.fediz.core.spi.SignInQueryCallback;
+import org.apache.cxf.fediz.core.spi.WAuthCallback;
+import org.apache.cxf.fediz.core.spi.WReqCallback;
+import org.apache.cxf.fediz.core.util.DOMUtils;
+import org.apache.wss4j.common.ext.WSPasswordCallback;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.dom.WSConstants;
+import org.apache.wss4j.dom.WSDataRef;
+import org.apache.wss4j.dom.WSDocInfo;
+import org.apache.wss4j.dom.WSSConfig;
+import org.apache.wss4j.dom.WSSecurityEngine;
+import org.apache.wss4j.dom.WSSecurityEngineResult;
+import org.apache.wss4j.dom.handler.RequestData;
+import org.apache.wss4j.dom.processor.EncryptedDataProcessor;
+import org.apache.wss4j.dom.processor.Processor;
+import org.apache.wss4j.dom.util.XmlSchemaDateFormat;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FederationProcessorImpl implements FedizProcessor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FederationProcessorImpl.class);
+
+    /**
+     * Default constructor
+     */
+    public FederationProcessorImpl() {
+        super();
+    }
+
+    @Override
+    public FedizResponse processRequest(FedizRequest request,
+                                             FedizContext config)
+        throws ProcessingException {
+        
+        if (!(config.getProtocol() instanceof FederationProtocol)) {
+            LOG.error("Unsupported protocol");
+            throw new IllegalStateException("Unsupported protocol");
+        }
+        FedizResponse response = null;
+        if (FederationConstants.ACTION_SIGNIN.equals(request.getWa())) {
+            response = this.processSignInRequest(request, config);
+        } else {
+            LOG.error("Invalid action '" + request.getWa() + "'");
+            throw new ProcessingException(TYPE.INVALID_REQUEST);
+        }
+        return response;
+    }
+    
+
+    public Document getMetaData(FedizContext config) throws ProcessingException {
+        return new MetadataWriter().getMetaData(config);
+    }
+    
+    protected FedizResponse processSignInRequest(
+            FedizRequest request, FedizContext config)
+        throws ProcessingException {
+        
+        byte[] wresult = request.getWresult().getBytes();
+
+        Document doc = null;
+        Element el = null;
+        try {
+            doc = DOMUtils.readXml(new ByteArrayInputStream(wresult));
+            el = doc.getDocumentElement();
+
+        } catch (Exception e) {
+            LOG.warn("Failed to parse wresult: " + e.getMessage());
+            throw new ProcessingException(TYPE.INVALID_REQUEST);
+        }
+
+        if ("RequestSecurityTokenResponseCollection".equals(el.getLocalName())) {
+            el = DOMUtils.getFirstElement(el);
+        }
+        if (!"RequestSecurityTokenResponse".equals(el.getLocalName())) {
+            LOG.warn("Unexpected root element of wresult: '" + el.getLocalName() + "'");
+            throw new ProcessingException(TYPE.INVALID_REQUEST);
+        }
+        el = DOMUtils.getFirstElement(el);
+        Element rst = null;
+        Element lifetimeElem = null;
+        String tt = null;
+
+        while (el != null) {
+            String ln = el.getLocalName();
+            if (FederationConstants.WS_TRUST_13_NS.equals(el.getNamespaceURI()) 
+                || FederationConstants.WS_TRUST_2005_02_NS.equals(el.getNamespaceURI())) {
+                if ("Lifetime".equals(ln)) {
+                    lifetimeElem = el;
+                } else if ("RequestedSecurityToken".equals(ln)) {
+                    rst = DOMUtils.getFirstElement(el);
+                } else if ("TokenType".equals(ln)) {
+                    tt = DOMUtils.getContent(el);
+                }
+            }
+            el = DOMUtils.getNextElement(el);
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("RST: " + ((rst != null) ? rst.toString() : "null"));
+            LOG.debug("Lifetime: "
+                    + ((lifetimeElem != null) ? lifetimeElem.toString()
+                            : "null"));
+            LOG.debug("Tokentype: " + ((tt != null) ? tt.toString() : "null"));
+        }
+        if (rst == null) {
+            LOG.warn("RequestedSecurityToken element not found in wresult");
+            throw new ProcessingException(TYPE.BAD_REQUEST);
+        }
+        LifeTime lifeTime = null;
+        if (lifetimeElem != null) {
+            lifeTime = processLifeTime(lifetimeElem);
+        }
+
+        if (config.isDetectExpiredTokens() && lifeTime != null) {
+            Date currentDate = new Date();
+            if (currentDate.after(lifeTime.getExpires())) {
+                LOG.warn("RSTR Lifetime expired");
+                throw new ProcessingException(TYPE.TOKEN_EXPIRED);
+            }
+            DateTime currentTime = new DateTime();
+            DateTime validFrom = new DateTime(lifeTime.created);
+            currentTime = currentTime.plusSeconds(config.getMaximumClockSkew().intValue());
+            if (validFrom.isAfter(currentTime)) {
+                LOG.debug("RSTR Lifetime not yet valid");
+                throw new ProcessingException(TYPE.TOKEN_INVALID);
+            }
+        }
+        
+        // Check to see if RST is encrypted
+        if ("EncryptedData".equals(rst.getLocalName())
+            && WSConstants.ENC_NS.equals(rst.getNamespaceURI())) {
+            Element decryptedRST = decryptEncryptedRST(rst, config);
+            if (decryptedRST != null) {
+                rst = decryptedRST;
+            }
+        }
+        
+        TokenValidatorResponse validatorResponse = null;
+        List<TokenValidator> validators = ((FederationProtocol)config.getProtocol()).getTokenValidators();
+        for (TokenValidator validator : validators) {
+            boolean canHandle = false;
+            if (tt != null) {
+                canHandle = validator.canHandleTokenType(tt);
+            } else {
+                canHandle = validator.canHandleToken(rst);
+            }
+            if (canHandle) {
+                try {
+                    TokenValidatorRequest validatorRequest = 
+                        new TokenValidatorRequest(rst, request.getCerts());
+                    validatorResponse = validator.validateAndProcessToken(validatorRequest, config);
+                } catch (ProcessingException ex) {
+                    throw ex;
+                } catch (Exception ex) {
+                    LOG.warn("Failed to validate token", ex);
+                    throw new ProcessingException(TYPE.TOKEN_INVALID);
+                }
+                break;
+            } else {
+                LOG.warn("No security token validator found for '" + tt + "'");
+                throw new ProcessingException(TYPE.BAD_REQUEST);
+            }
+        }
+
+        // Check whether token already used for signin
+        if (validatorResponse.getUniqueTokenId() != null
+                && config.isDetectReplayedTokens()) {
+            // Check whether token has already been processed once, prevent
+            // replay attack
+            if (!config.getTokenReplayCache().contains(validatorResponse.getUniqueTokenId())) {
+                // not cached
+                Date expires = null;
+                if (lifeTime != null && lifeTime.getExpires() != null) {
+                    expires = lifeTime.getExpires();
+                } else {
+                    expires = validatorResponse.getExpires();
+                }
+                if (expires != null) {
+                    Date currentTime = new Date();
+                    long ttl = expires.getTime() - currentTime.getTime();
+                    config.getTokenReplayCache().add(validatorResponse.getUniqueTokenId(), ttl / 1000L);
+                } else {
+                    config.getTokenReplayCache().add(validatorResponse.getUniqueTokenId());
+                }
+            } else {
+                LOG.error("Replay attack with token id: " + validatorResponse.getUniqueTokenId());
+                throw new ProcessingException("Replay attack with token id: "
+                        + validatorResponse.getUniqueTokenId(), TYPE.TOKEN_REPLAY);
+            }
+        }
+
+        FedizResponse fedResponse = new FedizResponse(
+                validatorResponse.getUsername(), validatorResponse.getIssuer(),
+                validatorResponse.getRoles(), validatorResponse.getClaims(),
+                validatorResponse.getAudience(),
+                (lifeTime != null) ? lifeTime.getCreated() : null,
+                        (lifeTime != null) ? lifeTime.getExpires() : null, rst,
+                            validatorResponse.getUniqueTokenId());
+
+        return fedResponse;
+    }
+    
+    private Element decryptEncryptedRST(
+        Element encryptedRST,
+        FedizContext config
+    ) throws ProcessingException {
+
+        KeyManager decryptionKeyManager = config.getDecryptionKey();
+        if (decryptionKeyManager == null || decryptionKeyManager.getCrypto() == null) {
+            LOG.debug(
+                "We must have a decryption Crypto instance configured to decrypt encrypted tokens"
+            );
+            throw new ProcessingException(TYPE.BAD_REQUEST);
+        }
+        String keyPassword = decryptionKeyManager.getKeyPassword();
+        if (keyPassword == null) {
+            LOG.debug(
+                "We must have a decryption key password to decrypt encrypted tokens"
+            );
+            throw new ProcessingException(TYPE.BAD_REQUEST);
+        }
+        
+        EncryptedDataProcessor proc = new EncryptedDataProcessor();
+        WSDocInfo docInfo = new WSDocInfo(encryptedRST.getOwnerDocument());
+        RequestData data = new RequestData();
+        
+        // Disable WSS4J processing of the (decrypted) SAML Token
+        WSSConfig wssConfig = WSSConfig.getNewInstance();
+        wssConfig.setProcessor(WSSecurityEngine.SAML_TOKEN, new NOOpProcessor());
+        wssConfig.setProcessor(WSSecurityEngine.SAML2_TOKEN, new NOOpProcessor());
+        data.setWssConfig(wssConfig);
+        
+        data.setDecCrypto(decryptionKeyManager.getCrypto());
+        data.setCallbackHandler(new DecryptionCallbackHandler(keyPassword));
+        try {
+            List<WSSecurityEngineResult> result =
+                proc.handleToken(encryptedRST, data, docInfo);
+            if (result.size() > 0) {
+                @SuppressWarnings("unchecked")
+                List<WSDataRef> dataRefs = 
+                    (List<WSDataRef>)result.get(result.size() - 1).get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
+                if (dataRefs != null && dataRefs.size() > 0) {
+                    return dataRefs.get(0).getProtectedElement();
+                }
+            }
+        } catch (WSSecurityException e) {
+            LOG.debug(e.getMessage(), e);
+            throw new ProcessingException(TYPE.TOKEN_INVALID);
+        }
+        return null;
+    }
+
+    private LifeTime processLifeTime(Element lifetimeElem) throws ProcessingException {
+        try {
+            Element createdElem = DOMUtils.getFirstChildWithName(lifetimeElem,
+                    WSConstants.WSU_NS, WSConstants.CREATED_LN);
+            DateFormat zulu = new XmlSchemaDateFormat();
+
+            Date created = zulu.parse(DOMUtils.getContent(createdElem));
+
+            Element expiresElem = DOMUtils.getFirstChildWithName(lifetimeElem,
+                    WSConstants.WSU_NS, WSConstants.EXPIRES_LN);
+            Date expires = zulu.parse(DOMUtils.getContent(expiresElem));
+
+            return new LifeTime(created, expires);
+
+        } catch (ParseException e) {
+            LOG.error("Failed to parse lifetime element in wresult: " + e.getMessage());
+            throw new ProcessingException(TYPE.BAD_REQUEST);
+        }
+    }
+
+    public class LifeTime {
+
+        private Date created;
+        private Date expires;
+
+        public LifeTime(Date created, Date expires) {
+            this.created = created;
+            this.expires = expires;
+        }
+
+        public Date getCreated() {
+            return created;
+        }
+
+        public Date getExpires() {
+            return expires;
+        }
+
+    }
+
+    @Override
+    public String createSignInRequest(HttpServletRequest request, FedizContext config)
+        throws ProcessingException {
+
+        String redirectURL = null;
+        try {
+            if (!(config.getProtocol() instanceof FederationProtocol)) {
+                LOG.error("Unsupported protocol");
+                throw new IllegalStateException("Unsupported protocol");
+            }
+            
+            String issuerURL = resolveIssuer(request, config);
+            LOG.info("Issuer url: " + issuerURL);
+            if (issuerURL != null && issuerURL.length() > 0) {
+                redirectURL = issuerURL;
+            }
+            
+            String wAuth = resolveAuthenticationType(request, config);
+            LOG.info("WAuth: " + wAuth);
+            
+            String wReq = resolveRequest(request, config);
+            LOG.info("WReq: " + wReq);
+            
+            String homeRealm = resolveHomeRealm(request, config);
+            LOG.info("HomeRealm: " + homeRealm);
+            
+            String freshness = resolveFreshness(request, config);
+            LOG.info("Freshness: " + freshness);
+            
+            String signInQuery = resolveSignInQuery(request, config);
+            LOG.info("SignIn Query: " + signInQuery);
+            
+             
+            StringBuilder sb = new StringBuilder();
+            sb.append(FederationConstants.PARAM_ACTION).append('=').append(FederationConstants.ACTION_SIGNIN);
+            
+            String reply = ((FederationProtocol)config.getProtocol()).getReply();
+            if (reply == null || reply.length() == 0) {
+                reply = request.getRequestURL().toString();
+            } else {
+                try {
+                    new URL(reply);
+                } catch (MalformedURLException ex) {
+                    if (reply.startsWith("/")) {
+                        reply = extractFullContextPath(request).concat(reply.substring(1));
+                    } else {
+                        reply = extractFullContextPath(request).concat(reply);
+                    }
+                }
+            }
+            
+            LOG.debug("wreply=" + reply);
+            sb.append('&').append(FederationConstants.PARAM_REPLY).append('=');
+            sb.append(URLEncoder.encode(reply, "UTF-8"));
+
+            String realm = resolveWTRealm(request, config);
+            LOG.debug("wtrealm=" + realm);
+
+            //add wtrealm parameter
+            sb.append('&').append(FederationConstants.PARAM_TREALM).append('=')
+                .append(URLEncoder.encode(realm, "UTF-8"));
+            
+            // add authentication type parameter wauth if set
+            if (wAuth != null && wAuth.length() > 0) {
+                sb.append('&').append(FederationConstants.PARAM_AUTH_TYPE).append('=')
+                    .append(URLEncoder.encode(wAuth, "UTF-8"));
+            }
+            
+            // add tokenRequest parameter wreq if set
+            if (wReq != null && wReq.length() > 0) {
+                sb.append('&').append(FederationConstants.PARAM_REQUEST).append('=')
+                    .append(URLEncoder.encode(wReq, "UTF-8"));
+            }
+            
+            // add home realm parameter whr if set
+            if (homeRealm != null && homeRealm.length() > 0) {
+                sb.append('&').append(FederationConstants.PARAM_HOME_REALM).append('=')
+                    .append(URLEncoder.encode(homeRealm, "UTF-8"));
+            }
+            
+            // add freshness parameter wfresh if set
+            if (freshness != null && freshness.length() > 0) {
+                sb.append('&').append(FederationConstants.PARAM_FRESHNESS).append('=')
+                    .append(URLEncoder.encode(freshness, "UTF-8"));
+            }
+            
+            // add current time parameter wct
+            Date creationTime = new Date();
+            XmlSchemaDateFormat fmt = new XmlSchemaDateFormat();
+            String wct = fmt.format(creationTime);
+            sb.append('&').append(FederationConstants.PARAM_CURRENT_TIME).append('=')
+            .append(URLEncoder.encode(wct, "UTF-8"));
+            
+            // add signin query extensions
+            if (signInQuery != null && signInQuery.length() > 0) {
+                sb.append('&').append(signInQuery);
+            }
+            
+            redirectURL = redirectURL + "?" + sb.toString();
+        } catch (Exception ex) {
+            LOG.error("Failed to create SignInRequest", ex);
+            throw new ProcessingException("Failed to create SignInRequest");
+        }        
+        return redirectURL;
+    }
+
+    @Override
+    public String createSignOutRequest(HttpServletRequest request, FedizContext config)
+        throws ProcessingException {
+
+        String redirectURL = null;
+        try {
+            if (!(config.getProtocol() instanceof FederationProtocol)) {
+                LOG.error("Unsupported protocol");
+                throw new IllegalStateException("Unsupported protocol");
+            }
+
+            String issuerURL = resolveIssuer(request, config);
+            LOG.info("Issuer url: " + issuerURL);
+            if (issuerURL != null && issuerURL.length() > 0) {
+                redirectURL = issuerURL;
+            }
+
+            StringBuilder sb = new StringBuilder();
+            sb.append(FederationConstants.PARAM_ACTION).append('=').append(FederationConstants.ACTION_SIGNOUT);
+
+            String logoutRedirectTo = config.getLogoutRedirectTo();
+            if (logoutRedirectTo != null && !logoutRedirectTo.isEmpty()) {
+
+                if (logoutRedirectTo.startsWith("/")) {
+                    logoutRedirectTo = extractFullContextPath(request).concat(logoutRedirectTo.substring(1));
+                } else {
+                    logoutRedirectTo = extractFullContextPath(request).concat(logoutRedirectTo);
+                }
+
+                LOG.debug("wreply=" + logoutRedirectTo);
+
+                sb.append('&').append(FederationConstants.PARAM_REPLY).append('=');
+                sb.append(URLEncoder.encode(logoutRedirectTo, "UTF-8"));
+            }
+
+            redirectURL = redirectURL + "?" + sb.toString();
+        } catch (Exception ex) {
+            LOG.error("Failed to create SignInRequest", ex);
+            throw new ProcessingException("Failed to create SignInRequest");
+        }
+        return redirectURL;
+    }
+
+    private String resolveSignInQuery(HttpServletRequest request, FedizContext config)
+        throws IOException, UnsupportedCallbackException, UnsupportedEncodingException {
+        Object signInQueryObj = ((FederationProtocol)config.getProtocol()).getSignInQuery();
+        String signInQuery = null;
+        if (signInQueryObj != null) {
+            if (signInQueryObj instanceof String) {
+                signInQuery = (String)signInQueryObj;
+            } else if (signInQueryObj instanceof CallbackHandler) {
+                CallbackHandler frCB = (CallbackHandler)signInQueryObj;
+                SignInQueryCallback callback = new SignInQueryCallback(request);
+                frCB.handle(new Callback[] {callback});
+                Map<String, String> signInQueryMap = callback.getSignInQueryParamMap();
+                StringBuilder sbQuery = new StringBuilder();
+                for (String key : signInQueryMap.keySet()) {
+                    if (sbQuery.length() > 0) {
+                        sbQuery.append("&");
+                    }
+                    sbQuery.append(key).append('=').
+                    append(URLEncoder.encode(signInQueryMap.get(key), "UTF-8"));
+                }
+                signInQuery = sbQuery.toString();
+               
+            }
+        }
+        return signInQuery;
+    }
+
+    private String resolveFreshness(HttpServletRequest request, FedizContext config) throws IOException,
+        UnsupportedCallbackException {
+        Object freshnessObj = ((FederationProtocol)config.getProtocol()).getFreshness();
+        String freshness = null;
+        if (freshnessObj != null) {
+            if (freshnessObj instanceof String) {
+                freshness = (String)freshnessObj;
+            } else if (freshnessObj instanceof CallbackHandler) {
+                CallbackHandler frCB = (CallbackHandler)freshnessObj;
+                FreshnessCallback callback = new FreshnessCallback(request);
+                frCB.handle(new Callback[] {callback});
+                freshness = callback.getFreshness();
+            }
+        }
+        return freshness;
+    }
+
+    private String resolveHomeRealm(HttpServletRequest request, FedizContext config) throws IOException,
+        UnsupportedCallbackException {
+        Object homeRealmObj = ((FederationProtocol)config.getProtocol()).getHomeRealm();
+        String homeRealm = null;
+        if (homeRealmObj != null) {
+            if (homeRealmObj instanceof String) {
+                homeRealm = (String)homeRealmObj;
+            } else if (homeRealmObj instanceof CallbackHandler) {
+                CallbackHandler hrCB = (CallbackHandler)homeRealmObj;
+                HomeRealmCallback callback = new HomeRealmCallback(request);
+                hrCB.handle(new Callback[] {callback});
+                homeRealm = callback.getHomeRealm();
+            }
+        }
+        return homeRealm;
+    }
+
+    private String resolveAuthenticationType(HttpServletRequest request, FedizContext config)
+        throws IOException, UnsupportedCallbackException {
+        Object wAuthObj = ((FederationProtocol)config.getProtocol()).getAuthenticationType();
+        String wAuth = null;
+        if (wAuthObj != null) {
+            if (wAuthObj instanceof String) {
+                wAuth = (String)wAuthObj;
+            } else if (wAuthObj instanceof CallbackHandler) {
+                CallbackHandler wauthCB = (CallbackHandler)wAuthObj;
+                WAuthCallback callback = new WAuthCallback(request);
+                wauthCB.handle(new Callback[] {callback});
+                wAuth = callback.getWauth();
+            }  
+        }
+        return wAuth;
+    }
+    
+    private String resolveRequest(HttpServletRequest request, FedizContext config)
+        throws IOException, UnsupportedCallbackException {
+        Object wReqObj = ((FederationProtocol)config.getProtocol()).getRequest();
+        String wReq = null;
+        if (wReqObj != null) {
+            if (wReqObj instanceof String) {
+                wReq = (String)wReqObj;
+            } else if (wReqObj instanceof CallbackHandler) {
+                CallbackHandler wauthCB = (CallbackHandler)wReqObj;
+                WReqCallback callback = new WReqCallback(request);
+                wauthCB.handle(new Callback[] {callback});
+                wReq = callback.getWreq();
+            }  
+        }
+        return wReq;
+    }
+
+    private String resolveIssuer(HttpServletRequest request, FedizContext config) throws IOException,
+        UnsupportedCallbackException {
+        Object issuerObj = ((FederationProtocol)config.getProtocol()).getIssuer();
+        String issuerURL = null;
+        if (issuerObj instanceof String) {
+            issuerURL = (String)issuerObj;
+        } else if (issuerObj instanceof CallbackHandler) {
+            CallbackHandler issuerCB = (CallbackHandler)issuerObj;
+            IDPCallback callback = new IDPCallback(request);
+            issuerCB.handle(new Callback[] {callback});
+            issuerURL = callback.getIssuerUrl().toString();
+        }
+        return issuerURL;
+    }
+
+    private String resolveWTRealm(HttpServletRequest request, FedizContext config) throws IOException,
+        UnsupportedCallbackException {
+        Object wtRealmObj = ((FederationProtocol)config.getProtocol()).getRealm();
+        String wtRealm = null;
+        if (wtRealmObj != null) {
+            if (wtRealmObj instanceof String) {
+                wtRealm = (String)wtRealmObj;
+            } else if (wtRealmObj instanceof CallbackHandler) {
+                CallbackHandler hrCB = (CallbackHandler)wtRealmObj;
+                RealmCallback callback = new RealmCallback(request);
+                hrCB.handle(new Callback[] {callback});
+                wtRealm = callback.getRealm();
+            }
+        } else {
+            wtRealm = extractFullContextPath(request); //default value
+        }
+        return wtRealm;
+    }
+
+
+    private String extractFullContextPath(HttpServletRequest request) throws MalformedURLException {
+        String result = null;
+        String contextPath = request.getContextPath();
+        String requestUrl = request.getRequestURL().toString();
+        String requestPath = new URL(requestUrl).getPath();
+        // Cut request path of request url and add context path if not ROOT
+        if (requestPath != null && requestPath.length() > 0) {
+            int lastIndex = requestUrl.lastIndexOf(requestPath);
+            result = requestUrl.substring(0, lastIndex);
+        } else {
+            result = requestUrl;
+        }
+        if (contextPath != null && contextPath.length() > 0) {
+            // contextPath contains starting slash
+            result = result + contextPath + "/";
+        } else {
+            result = result + "/";
+        }
+        return result;
+    }
+    
+    private static class DecryptionCallbackHandler implements CallbackHandler {
+        
+        private final String password;
+        
+        public DecryptionCallbackHandler(String password) {
+            this.password = password;
+        }
+
+        @Override
+        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+            for (int i = 0; i < callbacks.length; i++) {
+                if (callbacks[i] instanceof WSPasswordCallback) {
+                    WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
+                    pc.setPassword(password);
+                } else {
+                    throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
+                }
+            }
+        }
+        
+    }
+
+    private static class NOOpProcessor implements Processor {
+
+        @Override
+        public List<WSSecurityEngineResult> handleToken(Element arg0, RequestData arg1, WSDocInfo arg2)
+            throws WSSecurityException {
+            return new ArrayList<WSSecurityEngineResult>();
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessor.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessor.java
new file mode 100644
index 0000000..1081f05
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessor.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cxf.fediz.core.processor;
+
+import javax.servlet.http.HttpServletRequest;
+import org.w3c.dom.Document;
+import org.apache.cxf.fediz.core.config.FedizContext;
+import org.apache.cxf.fediz.core.exception.ProcessingException;
+
+
+public interface FedizProcessor {
+
+    FedizResponse processRequest(FedizRequest request, FedizContext config) throws ProcessingException;
+    
+    String createSignInRequest(HttpServletRequest request, FedizContext config) throws ProcessingException;
+
+    String createSignOutRequest(HttpServletRequest request, FedizContext config) throws ProcessingException;
+
+    Document getMetaData(FedizContext config) throws ProcessingException;
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessorFactory.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessorFactory.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessorFactory.java
new file mode 100644
index 0000000..c44a40b
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizProcessorFactory.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cxf.fediz.core.processor;
+
+import org.apache.cxf.fediz.core.config.FederationProtocol;
+import org.apache.cxf.fediz.core.config.Protocol;
+// import org.apache.cxf.fediz.core.config.SAMLProtocol;
+
+/**
+ * A Factory to return FedizProcessor instances depending on the Protocol
+ */
+public final class FedizProcessorFactory {
+    
+    private FedizProcessorFactory() {
+        // complete
+    }
+
+    public static FedizProcessor newFedizProcessor(Protocol protocol) {
+        if (protocol instanceof FederationProtocol) {
+            return new FederationProcessorImpl();
+        } /*else if (protocol instanceof SAMLProtocol) {
+            return new SAMLProcessorImpl();
+        }*/
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizRequest.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizRequest.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizRequest.java
new file mode 100644
index 0000000..bf296e5
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizRequest.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cxf.fediz.core.processor;
+
+import java.io.Serializable;
+import java.security.cert.Certificate;
+
+public class FedizRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    
+    private String wa;
+    private String wresult;
+    private String wct;
+    private Certificate[] certs;
+
+
+    public String getWct() {
+        return wct;
+    }
+    public void setWct(String wct) {
+        this.wct = wct;
+    }
+
+    public String getWa() {
+        return wa;
+    }
+    public void setWa(String wa) {
+        this.wa = wa;
+    }
+    public String getWresult() {
+        return wresult;
+    }
+    public void setWresult(String wresult) {
+        this.wresult = wresult;
+    }
+    public Certificate[] getCerts() {
+        return certs;
+    }
+    public void setCerts(Certificate[] certs) {
+        this.certs = certs;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/08af52b6/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizResponse.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizResponse.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizResponse.java
new file mode 100644
index 0000000..b392ad2
--- /dev/null
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FedizResponse.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.cxf.fediz.core.processor;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.fediz.core.Claim;
+
+public class FedizResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    
+    private String audience;
+    private String username;
+    private List<String> roles;
+    private String issuer;
+    private List<Claim> claims;
+    private Element token;
+    private String uniqueTokenId;
+
+    /**
+     * Created time
+     */
+    private Date tokenCreated;
+
+    /**
+     * Expiration time
+     */
+    private Date tokenExpires;
+
+    //CHECKSTYLE:OFF
+    public FedizResponse(String username, String issuer, List<String> roles, List<Claim> claims, String audience, Date created, Date expires, Element token, String uniqueTokenId) {
+        this.username = username;
+        this.issuer = issuer;
+        this.roles = roles;
+        this.claims = claims;
+        this.audience = audience;
+        this.tokenCreated = created;
+        this.tokenExpires = expires;
+        this.token = token;
+        this.uniqueTokenId = uniqueTokenId;
+    }
+
+    public String getUniqueTokenId() {
+        return uniqueTokenId;
+    }
+
+    public String getAudience() {
+        return audience;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public List<String> getRoles() {
+        if (roles == null) {
+            return null;
+        }
+        return Collections.unmodifiableList(roles);
+    }
+
+    public String getIssuer() {
+        return issuer;
+    }
+
+    public List<Claim> getClaims() {
+        if (claims == null) {
+            return null;
+        }
+        return Collections.unmodifiableList(claims);
+    }
+
+    public Date getTokenCreated() {
+        return tokenCreated;
+    }
+
+    public Date getTokenExpires() {
+        return tokenExpires;
+    }
+
+    public Element getToken() {
+        return token;
+    }
+
+
+}


Mime
View raw message