You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by jb...@apache.org on 2016/01/07 11:39:21 UTC

[2/4] cxf-fediz git commit: [FEDIZ-143] Home Realm Discovery based on OIDC login_hint

[FEDIZ-143] Home Realm Discovery based on OIDC login_hint


Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/24af6222
Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/24af6222
Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/24af6222

Branch: refs/heads/master
Commit: 24af6222343223faffa2b00646a49e182604da6d
Parents: ecb9ce6
Author: Jan Bernhardt <jb...@talend.com>
Authored: Wed Jan 6 17:08:10 2016 +0100
Committer: Jan Bernhardt <jb...@talend.com>
Committed: Thu Jan 7 11:13:34 2016 +0100

----------------------------------------------------------------------
 .../apache/cxf/fediz/core/config/Protocol.java  | 30 ++++++---
 .../core/processor/FederationProcessorImpl.java | 39 +++++++++---
 .../service/oidc/HomeRealmCallbackHandler.java  | 64 -------------------
 .../handler/hrd/ClientIdHomeRealmDiscovery.java | 67 ++++++++++++++++++++
 .../hrd/LoginHintHomeRealmDiscovery.java        | 64 +++++++++++++++++++
 5 files changed, 182 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/24af6222/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 7468e76..f72a574 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
@@ -170,18 +170,28 @@ public abstract class Protocol {
         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();
+            List<Object> handler = new ArrayList<Object>();
+            String[] cbtHandler = cbt.getValue().split(",");
+            for (String cbh : cbtHandler) {
+                try {
+                    if (getClassloader() == null) {
+                        handler.add(ClassLoaderUtils.loadClass(cbh, this.getClass()).newInstance());
+                    } else {
+                        handler.add(getClassloader().loadClass(cbh).newInstance());
+                    }
+                } catch (Exception e) {
+                    LOG.error("Failed to create instance of " + cbh, e);
+                    //throw new IllegalStateException("Failed to create instance of " + cbt.getValue());
                 }
-            } catch (Exception e) {
-                LOG.error("Failed to create instance of " + cbt.getValue(), e);
-                throw new IllegalStateException("Failed to create instance of " + cbt.getValue());
-            }            
+            }
+            if (handler.size() == 1) {
+                // Backward compatible return handler directly if only one is configured
+                return handler.get(0);
+            } else {
+                return handler;
+            }
         } else {
-            LOG.error("Only String and Class are supported for '" + name + "'");
+            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/24af6222/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
index d74dfe6..be25b09 100644
--- 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
@@ -548,27 +548,50 @@ public class FederationProcessorImpl extends AbstractFedizProcessor {
         return freshness;
     }
 
-    private String resolveHomeRealm(HttpServletRequest request, FedizContext config) throws IOException,
-        UnsupportedCallbackException {
+    private String resolveHomeRealm(HttpServletRequest request, FedizContext config) {
         // Check if whr parameter was provided in request
         String homeRealm = request.getParameter(FederationConstants.PARAM_HOME_REALM);
-        
-        if (homeRealm == null || homeRealm.isEmpty()) {
+
+        if (homeRealm != null && !homeRealm.isEmpty()) {
+            LOG.debug("HomeRealm was defined as 'whr' request parameter and will be used for IDP redirect");
+        } else {
             // Check if home realm is set in configuration
             Object homeRealmObj = ((FederationProtocol)config.getProtocol()).getHomeRealm();
             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();
+                    homeRealm = resolveHomeRealm(homeRealmObj, request);
+                } else if (homeRealmObj instanceof List<?>) {
+                    for (Object cbh : (List<?>)homeRealmObj) {
+                        homeRealm = resolveHomeRealm(cbh, request);
+                        if (homeRealm != null) {
+                            LOG.debug("Home realm was found by {}", cbh.getClass());
+                            break;
+                        }
+                    }
                 }
             }
         }
+        LOG.debug("Users home realm will be set to {}", homeRealm);
         return homeRealm;
     }
+    
+    private String resolveHomeRealm(Object cbh, HttpServletRequest request) {
+        if (cbh instanceof CallbackHandler) {
+            CallbackHandler hrCBH = (CallbackHandler)cbh;
+            HomeRealmCallback callback = new HomeRealmCallback(request);
+            try {
+                hrCBH.handle(new Callback[] {callback});
+            } catch (IOException | UnsupportedCallbackException e) {
+                LOG.warn("Home Realm Callbackhandler caused an exception", e);
+            }
+            return callback.getHomeRealm();
+        } else {
+            LOG.warn("Callback Handler was not an instanceof CallbackHandler: {}", cbh);
+            return null;
+        }
+    }
 
     private String resolveAuthenticationType(HttpServletRequest request, FedizContext config) throws IOException,
         UnsupportedCallbackException {

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/24af6222/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/HomeRealmCallbackHandler.java
----------------------------------------------------------------------
diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/HomeRealmCallbackHandler.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/HomeRealmCallbackHandler.java
deleted file mode 100644
index 673d261..0000000
--- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/HomeRealmCallbackHandler.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * 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.service.oidc;
-
-import java.io.IOException;
-
-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.apache.cxf.fediz.core.spi.HomeRealmCallback;
-import org.apache.cxf.rs.security.oauth2.common.Client;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationContext;
-
-public class HomeRealmCallbackHandler implements CallbackHandler {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(HomeRealmCallbackHandler.class);
-
-    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-        for (int i = 0; i < callbacks.length; i++) {
-            if (callbacks[i] instanceof HomeRealmCallback) {
-                HomeRealmCallback callback = (HomeRealmCallback) callbacks[i];
-                
-                HttpServletRequest request = callback.getRequest();
-                String clientId = request.getParameter("client_id");
-                
-                if (clientId != null) {
-                    ApplicationContext ctx = ApplicationContextProvider.getApplicationContext();
-                    OAuthDataManager dataManager = (OAuthDataManager)ctx.getBean("oauthProvider");
-                    
-                    Client client = dataManager.getClient(clientId);
-                    if (client instanceof FedizClient) {
-                        callback.setHomeRealm(((FedizClient)client).getHomeRealm());
-                        LOG.debug("Retrieved home realm {}", callback.getHomeRealm());
-                    }
-                }
-                
-            } else {
-                throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
-            }
-        }
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/24af6222/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/ClientIdHomeRealmDiscovery.java
----------------------------------------------------------------------
diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/ClientIdHomeRealmDiscovery.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/ClientIdHomeRealmDiscovery.java
new file mode 100644
index 0000000..28c7734
--- /dev/null
+++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/ClientIdHomeRealmDiscovery.java
@@ -0,0 +1,67 @@
+/**
+ * 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.service.oidc.handler.hrd;
+
+import java.io.IOException;
+
+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.apache.cxf.fediz.core.spi.HomeRealmCallback;
+import org.apache.cxf.fediz.service.oidc.ApplicationContextProvider;
+import org.apache.cxf.fediz.service.oidc.FedizClient;
+import org.apache.cxf.fediz.service.oidc.OAuthDataManager;
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
+
+public class ClientIdHomeRealmDiscovery implements CallbackHandler {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ClientIdHomeRealmDiscovery.class);
+
+    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+        for (int i = 0; i < callbacks.length; i++) {
+            if (callbacks[i] instanceof HomeRealmCallback) {
+                HomeRealmCallback callback = (HomeRealmCallback) callbacks[i];
+                
+                HttpServletRequest request = callback.getRequest();
+                String clientId = request.getParameter("client_id");
+                
+                if (clientId != null) {
+                    ApplicationContext ctx = ApplicationContextProvider.getApplicationContext();
+                    OAuthDataManager dataManager = (OAuthDataManager)ctx.getBean("oauthProvider");
+                    
+                    Client client = dataManager.getClient(clientId);
+                    if (client instanceof FedizClient) {
+                        callback.setHomeRealm(((FedizClient)client).getHomeRealm());
+                        LOG.debug("Retrieved home realm {}", callback.getHomeRealm());
+                    }
+                }
+                
+            } else {
+                LOG.warn("Callback is not an inctance of HomeRealmCallback: {}", callbacks[i]);
+            }
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/24af6222/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/LoginHintHomeRealmDiscovery.java
----------------------------------------------------------------------
diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/LoginHintHomeRealmDiscovery.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/LoginHintHomeRealmDiscovery.java
new file mode 100644
index 0000000..9f91b63
--- /dev/null
+++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/handler/hrd/LoginHintHomeRealmDiscovery.java
@@ -0,0 +1,64 @@
+/**
+ * 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.service.oidc.handler.hrd;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.apache.cxf.fediz.core.spi.HomeRealmCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This callback handler uses the login_hint parameter defined in OpenID Connect to discover the users home realm.
+ * 
+ * It is expected that the login_hint will contain the users email address and that the domain name from the mail 
+ * address will be equal to the home realm identifier.
+ */
+public class LoginHintHomeRealmDiscovery implements CallbackHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LoginHintHomeRealmDiscovery.class);
+
+    public void handle(Callback[] callbacks) throws IOException,
+        UnsupportedCallbackException {
+        for (int i = 0; i < callbacks.length; i++) {
+            if (callbacks[i] instanceof HomeRealmCallback) {
+                HomeRealmCallback callback = (HomeRealmCallback) callbacks[i];
+                String loginHint = (String)callback.getRequest().getParameter("login_hint");
+                if (loginHint == null || loginHint.length() == 0) {
+                    LOG.debug("No login_hint found in request to set home realm");
+                } else {
+                    String[] homeRealm = loginHint.split("@");
+                    if (homeRealm.length == 2) {
+                        LOG.debug("Home realm '{}' found in request", homeRealm[1]);
+                        callback.setHomeRealm(homeRealm[1]);
+                    } else {
+                        LOG.warn("login_hint is not an email address: {}", loginHint);
+                    }
+                }
+            } else {
+                LOG.warn("Callback is not an inctance of HomeRealmCallback: {}", callbacks[i]);
+            }
+        }
+    }
+
+}
\ No newline at end of file