Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 6B210200CC7 for ; Sun, 16 Jul 2017 20:25:35 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 690EA1641C6; Sun, 16 Jul 2017 18:25:35 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id B2DB81641C4 for ; Sun, 16 Jul 2017 20:25:33 +0200 (CEST) Received: (qmail 72009 invoked by uid 500); 16 Jul 2017 18:25:32 -0000 Mailing-List: contact commits-help@oodt.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@oodt.apache.org Delivered-To: mailing list commits@oodt.apache.org Received: (qmail 72000 invoked by uid 99); 16 Jul 2017 18:25:32 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 16 Jul 2017 18:25:32 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 75978E96A8; Sun, 16 Jul 2017 18:25:31 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mattmann@apache.org To: commits@oodt.apache.org Message-Id: <6aea9083540a4ad19b5acfe5e3bbeb2c@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: oodt git commit: - add to Curation Services, only place it is used (is in Curator). Date: Sun, 16 Jul 2017 18:25:31 +0000 (UTC) archived-at: Sun, 16 Jul 2017 18:25:35 -0000 Repository: oodt Updated Branches: refs/heads/master 78dd55fda -> f1e5bed64 - add to Curation Services, only place it is used (is in Curator). Project: http://git-wip-us.apache.org/repos/asf/oodt/repo Commit: http://git-wip-us.apache.org/repos/asf/oodt/commit/f1e5bed6 Tree: http://git-wip-us.apache.org/repos/asf/oodt/tree/f1e5bed6 Diff: http://git-wip-us.apache.org/repos/asf/oodt/diff/f1e5bed6 Branch: refs/heads/master Commit: f1e5bed64691a18b1e383665f5b625879139b319 Parents: 78dd55f Author: Chris Mattmann Authored: Sun Jul 16 11:25:33 2017 -0700 Committer: Chris Mattmann Committed: Sun Jul 16 11:25:33 2017 -0700 ---------------------------------------------------------------------- .../cas/curation/service/CurationService.java | 2 + .../sso/AbstractWebBasedSingleSignOn.java | 90 ++++++ .../org/apache/oodt/security/sso/DummyImpl.java | 102 ++++++ .../apache/oodt/security/sso/OpenSSOImpl.java | 190 ++++++++++++ .../apache/oodt/security/sso/SingleSignOn.java | 85 +++++ .../oodt/security/sso/SingleSignOnFactory.java | 68 ++++ .../security/sso/opensso/IdentityDetails.java | 136 ++++++++ .../oodt/security/sso/opensso/SSOMetKeys.java | 81 +++++ .../oodt/security/sso/opensso/SSOProxy.java | 308 +++++++++++++++++++ .../sso/opensso/SingleSignOnException.java | 11 + .../oodt/security/sso/opensso/UserDetails.java | 97 ++++++ 11 files changed, 1170 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/cas/curation/service/CurationService.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/cas/curation/service/CurationService.java b/curator/services/src/main/java/org/apache/oodt/cas/curation/service/CurationService.java index d414f5c..cb1ca41 100644 --- a/curator/services/src/main/java/org/apache/oodt/cas/curation/service/CurationService.java +++ b/curator/services/src/main/java/org/apache/oodt/cas/curation/service/CurationService.java @@ -68,6 +68,8 @@ public class CurationService extends HttpServlet implements CuratorConfMetKeys { protected final static String FORMAT_HTML = "html"; protected final static String UNKNOWN_OUT_FORMAT = "Unsupported Output Format!"; + + protected SingleSignOn sso; /** * Default Constructor. http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/AbstractWebBasedSingleSignOn.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/AbstractWebBasedSingleSignOn.java b/curator/services/src/main/java/org/apache/oodt/security/sso/AbstractWebBasedSingleSignOn.java new file mode 100644 index 0000000..1ad57cb --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/AbstractWebBasedSingleSignOn.java @@ -0,0 +1,90 @@ +/* + * 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.oodt.security.sso; + +//JDK imports +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + * Abstract class providing an HTTP request and response interface pair to allow + * for persistence and management of state information related to SingleSignOn. + * + * @author mattmann + * @version $Revision$ + * + */ +public abstract class AbstractWebBasedSingleSignOn implements SingleSignOn { + + protected HttpServletResponse res; + + protected HttpServletRequest req; + + public AbstractWebBasedSingleSignOn() { + this.req = null; + this.res = null; + } + + /** + * Constructs a new {@link AbstractWebBasedSingleSignOn} with the given HTTP + * request and response. + * + * @param res + * The {@link HttpServletRequest}. + * @param req + * The {@link HttpServletResponse}. + */ + public AbstractWebBasedSingleSignOn(HttpServletResponse res, + HttpServletRequest req) { + this.res = res; + this.req = req; + } + + /** + * @return the res + */ + public HttpServletResponse getRes() { + return res; + } + + /** + * @param res + * the res to set + */ + public void setRes(HttpServletResponse res) { + this.res = res; + } + + /** + * @return the req + */ + public HttpServletRequest getReq() { + return req; + } + + /** + * @param req + * the req to set + */ + public void setReq(HttpServletRequest req) { + this.req = req; + } + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/DummyImpl.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/DummyImpl.java b/curator/services/src/main/java/org/apache/oodt/security/sso/DummyImpl.java new file mode 100644 index 0000000..dfc88be --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/DummyImpl.java @@ -0,0 +1,102 @@ +/* + * 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.oodt.security.sso; + +//JDK imports +import java.util.Collections; +import java.util.List; + +/** + * + * Dummy implementation of SSO auth -- if you're logged in, it logs you out. If + * you're logged out, it logs you in. Both are independent of the actual + * username/password combination you enter. On top of that, your username will + * always be guest. + * + * @author mattmann + * @version $Revision$ + * + */ +public class DummyImpl extends AbstractWebBasedSingleSignOn { + + private static final String DEFAULT_USERNAME = "guest"; + + private static final String DEFAULT_GROUP = "guest"; + + private boolean connected = false; + + /* + * (non-Javadoc) + * + * @see org.apache.oodt.cas.security.sso.SingleSignOn#getCurrentUsername() + */ + public String getCurrentUsername() { + return DEFAULT_USERNAME; + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.oodt.cas.security.sso.SingleSignOn#getLastConnectionStatus() + */ + public boolean getLastConnectionStatus() { + // TODO Auto-generated method stub + return this.connected; + } + + /* + * (non-Javadoc) + * + * @see org.apache.oodt.cas.security.sso.SingleSignOn#isLoggedIn() + */ + public boolean isLoggedIn() { + // TODO Auto-generated method stub + return this.connected; + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.oodt.cas.security.sso.SingleSignOn#login(java.lang.String, + * java.lang.String) + */ + public boolean login(String username, String password) { + this.connected = true; + return true; + } + + /* + * (non-Javadoc) + * + * @see org.apache.oodt.cas.security.sso.SingleSignOn#logout() + */ + public void logout() { + this.connected = false; + } + + /* (non-Javadoc) + * @see org.apache.oodt.cas.security.sso.SingleSignOn#retrieveGroupsForUser(java.lang.String) + */ + public List retrieveGroupsForUser(String username) { + return Collections.singletonList(DEFAULT_GROUP); + } + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/OpenSSOImpl.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/OpenSSOImpl.java b/curator/services/src/main/java/org/apache/oodt/security/sso/OpenSSOImpl.java new file mode 100755 index 0000000..0c0db54 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/OpenSSOImpl.java @@ -0,0 +1,190 @@ +/** + * 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.oodt.security.sso; + +import org.apache.commons.codec.binary.Base64; +import org.apache.oodt.security.sso.opensso.SSOMetKeys; +import org.apache.oodt.security.sso.opensso.SSOProxy; +import org.apache.oodt.security.sso.opensso.SingleSignOnException; +import org.apache.oodt.security.sso.opensso.UserDetails; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.servlet.http.Cookie; + +/** + * + * Connects to OpenSSO's authorization endpoint and authenticates a user, + * implementing the CAS {@link AbstractWebBasedSingleSignOn} interface. This + * class can be used in e.g., CAS curator to link into Open SSO. + */ +public class OpenSSOImpl extends AbstractWebBasedSingleSignOn implements + SSOMetKeys { + + private static final Logger LOG = Logger.getLogger(OpenSSOImpl.class + .getName()); + + private SSOProxy ssoProxy; + + /** + * Default constructor. + */ + public OpenSSOImpl() { + this.ssoProxy = new SSOProxy(); + } + + public String getCurrentUsername() { + String cookieVal = this.getCookieVal(USER_COOKIE_KEY); + if (cookieVal == null) { + // let's try and get the SSO token + // and pull the username from there + String ssoToken = this.getSSOToken(); + if (ssoToken != null) { + UserDetails details; + try { + details = this.ssoProxy.getUserAttributes(ssoToken); + } catch (Exception e) { + LOG.log(Level.SEVERE, e.getMessage()); + return UNKNOWN_USER; + } + return details.getAttributes().getMetadata(UID_ATTRIBUTE_NAME) != null ? details + .getAttributes().getMetadata(UID_ATTRIBUTE_NAME) : UNKNOWN_USER; + } else { + return UNKNOWN_USER; + } + } else { + return new String(Base64.decodeBase64(cookieVal.getBytes())); + } + } + + public boolean getLastConnectionStatus() { + return this.isLoggedIn(); + } + + public boolean isLoggedIn() { + // TODO: make sure the token is valid? + return (this.getSSOToken() != null); + } + + public boolean login(String username, String password) { + + String ssoToken; + try { + ssoToken = this.ssoProxy.authenticate(username, password); + } catch (Exception e) { + LOG.log(Level.SEVERE, e.getMessage()); + return false; + } + + this.addCookie(SSO_COOKIE_KEY, "\"" + ssoToken + "\""); + + this.addCookie(USER_COOKIE_KEY, + "\"" + new String(Base64.encodeBase64(username.getBytes())) + "\""); + + return true; + } + + public void logout() { + this.ssoProxy.logout(this.getSSOToken()); + this.clearCookie(SSO_COOKIE_KEY); + this.clearCookie(USER_COOKIE_KEY); + } + + /** + * Gets the SSO groups for the LMMP user, identified by her + * ssoAuth, where her User ID is provided by + * {@link OpenSSOImpl#getCurrentUsername()} and her Token is provided by + * {@link OpenSSOImpl#getSSOToken()}. + * + * @return A {@link List} of String LMMP groups for the User. + * @throws Exception + * If any error (e.g., HTTP REST error) occurs. + */ + public List getGroupsForUser() throws IOException, SingleSignOnException { + String token = this.getSSOToken(); + if (token == null) { + return Collections.EMPTY_LIST; + } else { + UserDetails details = this.ssoProxy.getUserAttributes(token); + // groups are formatted in this response to include whole + // principals, like lmmp-infra,...principal + // so split on "," and take the first token to get the group name + List groups = new Vector(); + for (String rawGroup : details.getRoles()) { + groups.add(rawGroup.split(",")[0]); + } + + return groups; + } + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.oodt.security.sso.SingleSignOn#retrieveGroupsForUser(java.lang + * .String) + */ + @Override + public List retrieveGroupsForUser(String username) { + // FIXME: not implemented yet + return Collections.EMPTY_LIST; + } + + protected String getSSOToken() { + String cookieVal = this.getCookieVal(SSO_COOKIE_KEY); + if (cookieVal != null) { + return cookieVal; + } else { + return null; + } + } + + private String getCookieVal(String name) { + Cookie[] cookies = this.req.getCookies(); + for (Cookie cookie : cookies) { + if (cookie.getName().equals(name)) { + return cookie.getValue().startsWith("\"") + && cookie.getValue().endsWith("\"") ? cookie.getValue().substring( + 1, cookie.getValue().length() - 1) : cookie.getValue(); + } + } + + return null; + } + + private void addCookie(String name, String val) { + Cookie userCookie = new Cookie(name, val); + userCookie.setPath("/"); + userCookie.setMaxAge((int) (System.currentTimeMillis() + (60 * 15))); + this.res.addCookie(userCookie); + } + + private void clearCookie(String name) { + Cookie userCookie = new Cookie(name, "blank"); + userCookie.setPath("/"); + userCookie.setMaxAge(0); + this.res.addCookie(userCookie); + } + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOn.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOn.java b/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOn.java new file mode 100644 index 0000000..3835bf8 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOn.java @@ -0,0 +1,85 @@ +/* + * 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.oodt.security.sso; + +//JDK imports +import java.util.List; + +/** + * + * The CAS java-based single sign on API. + * + * @author mattmann + * @version $Revision$ + * + */ +public interface SingleSignOn { + + /** + * Should return the current logged in Single Sign On username returned from + * the implementation-specific authentication API. + * + * @return A string representation of the current SSO username. + */ + String getCurrentUsername(); + + /** + * Returns true when the user is logged in, or false otherwise. + * + * @return True if the user is logged in, false otherwise. + */ + boolean isLoggedIn(); + + /** + * Logs the user with the provided username and + * password in to the SSO authentication mechanism. + * + * @param username + * The username credentials. + * @param password + * The password credentials. + * @return True if the login was successful, false otherwise. + */ + boolean login(String username, String password); + + /** + * Logs the current SSO user out of her session. + */ + void logout(); + + /** + * Should provide information (true or false) as to whether the last + * connection to the SSO authentication service was successful. + * + * @return True if the last authentication was successful, false otherwise. + */ + boolean getLastConnectionStatus(); + + /** + * Obtains a user's groups from the security principal that this SSO object + * talks to. + * + * @param username + * The username to obtain the groups for. + * @return A {@link List} of string group names obtained from the security + * principal. + **/ + List retrieveGroupsForUser(String username); + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOnFactory.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOnFactory.java b/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOnFactory.java new file mode 100644 index 0000000..e3753a6 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/SingleSignOnFactory.java @@ -0,0 +1,68 @@ +/* + * 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.oodt.security.sso; + + +//JDK imports +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * Object factory for creating {@link SingleSignOn}s from class name Strings. + * + * @author mattmann + * @version $Revision$ + * + */ +public final class SingleSignOnFactory { + + private static final Logger LOG = Logger.getLogger(SingleSignOnFactory.class + .getName()); + + @SuppressWarnings("unchecked") + public static AbstractWebBasedSingleSignOn getWebBasedSingleSignOn(String className) { + AbstractWebBasedSingleSignOn sso; + Class clazz; + + try { + clazz = (Class) Class.forName(className); + sso = clazz.newInstance(); + return sso; + } catch (ClassNotFoundException e) { + LOG.log(Level.SEVERE, e.getMessage()); + LOG.log(Level.WARNING, + "ClassNotFoundException when loading web based sso class " + + className + " Message: " + e.getMessage()); + } catch (InstantiationException e) { + LOG.log(Level.SEVERE, e.getMessage()); + LOG.log(Level.WARNING, + "InstantiationException when loading web based sso class " + + className + " Message: " + e.getMessage()); + } catch (IllegalAccessException e) { + LOG.log(Level.SEVERE, e.getMessage()); + LOG.log(Level.WARNING, + "IllegalAccessException when loading web based sso class " + + className + " Message: " + e.getMessage()); + } + + return null; + } + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/IdentityDetails.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/IdentityDetails.java b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/IdentityDetails.java new file mode 100755 index 0000000..97916f1 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/IdentityDetails.java @@ -0,0 +1,136 @@ +/** + * 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.oodt.security.sso.opensso; + +//JDK imports +import org.apache.oodt.cas.metadata.Metadata; + +import java.util.List; +import java.util.Vector; + +//OODT imports + +/** + * + * The response from a call to {@link SSOMetKeys#IDENTITY_READ_ENDPOINT}. + * + * @author mattmann + * @version $Revision$ + * + */ +public class IdentityDetails { + + private String name; + + private String type; + + private String realm; + + private List groups; + + private Metadata attributes; + + public IdentityDetails() { + this.name = null; + this.type = null; + this.realm = null; + this.groups = new Vector(); + this.attributes = new Metadata(); + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the type + */ + public String getType() { + return type; + } + + /** + * @param type + * the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * @return the realm + */ + public String getRealm() { + return realm; + } + + /** + * @param realm + * the realm to set + */ + public void setRealm(String realm) { + this.realm = realm; + } + + /** + * @return the groups + */ + public List getGroups() { + return groups; + } + + /** + * @param groups + * the groups to set + */ + public void setGroups(List groups) { + this.groups = groups; + } + + /** + * @return the attributes + */ + public Metadata getAttributes() { + return attributes; + } + + /** + * @param attributes + * the attributes to set + */ + public void setAttributes(Metadata attributes) { + this.attributes = attributes; + } + + public String toString() { + return "[name=" + this.name + ",type=" + this.type + ",realm=" + this.realm + ",roles=" + this.groups + + ",attributes=" + this.attributes.getMap() + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOMetKeys.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOMetKeys.java b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOMetKeys.java new file mode 100755 index 0000000..0e97221 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOMetKeys.java @@ -0,0 +1,81 @@ +/** + * 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.oodt.security.sso.opensso; + +/** + * + * Met keys for dealing with {@link SSOProxy}. + * + */ +public interface SSOMetKeys { + + /* service endpoints */ + String AUTHENTICATE_ENDPOINT = "https://host/opensso/identity/authenticate"; + + String IDENTITY_READ_ENDPOINT = "https://host/opensso/identity/read"; + + String IDENTITY_ATTRIBUTES_ENDPOINT = "https://host/opensso/identity/attributes"; + + String LOGOUT_ENDPOINT = "https://host/opensso/identity/logout"; + + /* cookie names */ + + String SSO_COOKIE_KEY = "iPlanetDirectoryPro"; + + String USER_COOKIE_KEY = "curationWebapp"; + + /* Identity Details response object */ + + String IDENTITY_DETAILS_NAME = "identitydetails.name"; + + String IDENTITY_DETAILS_TYPE = "identitydetails.type"; + + String IDENTITY_DETAILS_REALM = "identitydetails.realm"; + + String IDENTITY_DETAILS_GROUP = "identitydetails.group"; + + String IDENTITY_DETAILS_ATTR_NAME = "identitydetails.attribute.name"; + + String IDENTITY_DETAILS_ATTR_VALUE = "identitydetails.attribute.value"; + + String IDENTITY_DETAILS_ATTR_SKIP_LINE = "identitydetails.attribute="; + + /* User Details response object */ + String USER_DETAILS_TOKEN = "userdetails.token.id"; + + String USER_DETAILS_ROLE = "userdetails.role=id"; + + String USER_DETAILS_ATTR_NAME = "userdetails.attribute.name"; + + String USER_DETAILS_ATTR_VALUE = "userdetails.attribute.value"; + + String UID_ATTRIBUTE_NAME = "uid"; + + /* commands available from SSOProxy command line */ + String AUTH_COMMAND = "authenticate"; + + String IDENTITY_COMMAND = "identity"; + + String ATTRIBUTES_COMMAND = "attributes"; + + String LOGOUT_COMMAND = "logout"; + + /* general stuff */ + String UNKNOWN_USER = "Unknown"; + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOProxy.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOProxy.java b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOProxy.java new file mode 100755 index 0000000..5d77083 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SSOProxy.java @@ -0,0 +1,308 @@ +/** + * 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.oodt.security.sso.opensso; + + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.PostMethod; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * A client class to the services provided by the OpenSSO project. The descriptions of + * these services are here. + * + * @author mattmann + * @version $Revision$ + * + */ +public class SSOProxy implements SSOMetKeys { + + private static final Logger LOG = Logger.getLogger(SSOProxy.class.getName()); + private static final String AUTH_ENDPOINT; + private static final String AUTH_ENDPOINT_KEY = "AUTH_ENDPOINT"; + private static final String IDENT_READ_ENDPOINT; + private static final String IDENT_READ_ENDPOINT_KEY = "IDENT_READ_ENDPOINT"; + private static final String IDENT_ATTR_ENDPOINT; + private static final String IDENT_ATTR_ENDPOINT_KEY = "IDENT_ATTR_ENDPOINT"; + private static final String LOG_ENDPOINT; + private static final String LOG_ENDPOINT_KEY = "LOG_ENDPOINT"; + + static { + if (System.getProperty(AUTH_ENDPOINT_KEY) != null) { + AUTH_ENDPOINT = System.getProperty(AUTH_ENDPOINT_KEY); + } else { + AUTH_ENDPOINT = AUTHENTICATE_ENDPOINT; + } + if (System.getProperty(IDENT_READ_ENDPOINT_KEY) != null) { + IDENT_READ_ENDPOINT = System.getProperty(IDENT_READ_ENDPOINT_KEY); + } else { + IDENT_READ_ENDPOINT = IDENTITY_READ_ENDPOINT; + } + if (System.getProperty(IDENT_ATTR_ENDPOINT_KEY) != null) { + IDENT_ATTR_ENDPOINT = System.getProperty(IDENT_ATTR_ENDPOINT_KEY); + } else { + IDENT_ATTR_ENDPOINT = IDENTITY_ATTRIBUTES_ENDPOINT; + } + if (System.getProperty(LOG_ENDPOINT_KEY) != null) { + LOG_ENDPOINT = System.getProperty(LOG_ENDPOINT_KEY); + } else { + LOG_ENDPOINT = LOGOUT_ENDPOINT; + } + + LOG.log(Level.INFO, AUTH_ENDPOINT_KEY + " set to " + AUTH_ENDPOINT); + LOG.log(Level.INFO, IDENT_READ_ENDPOINT_KEY + " set to " + IDENT_READ_ENDPOINT); + LOG.log(Level.INFO, IDENT_ATTR_ENDPOINT_KEY + " set to " + IDENT_ATTR_ENDPOINT); + LOG.log(Level.INFO, LOG_ENDPOINT_KEY + " set to " + LOG_ENDPOINT); + } + + public String authenticate(String username, String password) { + HttpClient httpClient = new HttpClient(); + PostMethod post = new PostMethod(AUTH_ENDPOINT); + String response; + String ssoToken = null; + + NameValuePair[] data = { new NameValuePair("username", username), + new NameValuePair("password", password), + new NameValuePair("uri", "realm/lmmp") }; + + post.setRequestBody(data); + + try { + httpClient.executeMethod(post); + if (post.getStatusCode() != HttpStatus.SC_OK) { + throw new HttpException(post.getStatusLine().toString()); + } + response = post.getResponseBodyAsString().trim(); + ssoToken = response.substring(9); + } catch (Exception e) { + LOG.log(Level.SEVERE, e.getMessage()); + } finally { + post.releaseConnection(); + } + + return ssoToken; + } + + public IdentityDetails readIdentity(String username, String token) + throws IOException, SingleSignOnException { + HttpClient httpClient = new HttpClient(); + PostMethod post = new PostMethod(IDENT_READ_ENDPOINT); + LOG.log(Level.INFO, "Obtaining identity: username: [" + username + + "]: token: [" + token + "]: REST url: [" + IDENT_READ_ENDPOINT + + "]"); + NameValuePair[] data = { new NameValuePair("name", username), + new NameValuePair("admin", token) }; + + post.setRequestBody(data); + + httpClient.executeMethod(post); + if (post.getStatusCode() != HttpStatus.SC_OK) { + throw new SingleSignOnException(post.getStatusLine().toString()); + } + + return parseIdentityDetails(post.getResponseBodyAsString().trim()); + + } + + public UserDetails getUserAttributes(String token) throws IOException, SingleSignOnException { + HttpClient httpClient = new HttpClient(); + PostMethod post = new PostMethod(IDENT_ATTR_ENDPOINT); + LOG.log(Level.INFO, "Obtaining user attributes: token: [" + token + + "]: REST url: [" + IDENT_ATTR_ENDPOINT + "]"); + NameValuePair[] data = { new NameValuePair("subjectid", token) }; + + post.setRequestBody(data); + + httpClient.executeMethod(post); + if (post.getStatusCode() != HttpStatus.SC_OK) { + throw new SingleSignOnException(post.getStatusLine().toString()); + } + + return parseUserDetails(post.getResponseBodyAsString().trim()); + + } + + public void logout(String token) { + HttpClient httpClient = new HttpClient(); + PostMethod post = new PostMethod(LOG_ENDPOINT); + LOG.log(Level.INFO, "Logging out: token: [" + token + "]: REST url: [" + + LOG_ENDPOINT + "]"); + NameValuePair[] data = { new NameValuePair("subjectid", token) }; + post.setRequestBody(data); + + try { + httpClient.executeMethod(post); + if (post.getStatusCode() != HttpStatus.SC_OK) { + throw new HttpException(post.getStatusLine().toString()); + } + } catch (HttpException e) { + // TODO Auto-generated catch block + LOG.log(Level.SEVERE, e.getMessage()); + } catch (IOException e) { + // TODO Auto-generated catch block + LOG.log(Level.SEVERE, e.getMessage()); + } finally { + post.releaseConnection(); + } + } + + private IdentityDetails parseIdentityDetails(String serviceResponse) { + ByteArrayInputStream is = new ByteArrayInputStream(serviceResponse + .getBytes()); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + IdentityDetails details = new IdentityDetails(); + String line = null, lastAttrKeyRead = null; + + try { + while ((line = br.readLine()) != null) { + if (line.equals(IDENTITY_DETAILS_ATTR_SKIP_LINE)) { + continue; + } + String key, val; + if (line.startsWith(IDENTITY_DETAILS_REALM)) { + // can't parse it the same way + key = line.substring(0, IDENTITY_DETAILS_REALM.length()); + val = line.substring(IDENTITY_DETAILS_REALM.length() + 1); + } else { + String[] lineToks = line.split("="); + key = lineToks[0]; + val = lineToks[1]; + } + + if (key.equals(IDENTITY_DETAILS_NAME)) { + details.setName(val); + } else if (key.equals(IDENTITY_DETAILS_TYPE)) { + details.setType(val); + } else if (key.equals(IDENTITY_DETAILS_REALM)) { + details.setRealm(val); + } else if (key.equals(IDENTITY_DETAILS_GROUP)) { + details.getGroups().add(val); + } else if (key.equals(IDENTITY_DETAILS_ATTR_NAME)) { + lastAttrKeyRead = val; + } else if (key.equals(IDENTITY_DETAILS_ATTR_VALUE)) { + details.getAttributes().addMetadata(lastAttrKeyRead, val); + } + } + } catch (IOException e) { + LOG.log(Level.SEVERE, e.getMessage()); + LOG.log(Level.WARNING, "Error reading service response line: [" + line + + "]: Message: " + e.getMessage()); + } finally { + try { + is.close(); + } catch (Exception ignore) { + } + + try { + br.close(); + } catch (Exception ignore) { + } + + } + + return details; + } + + private UserDetails parseUserDetails(String serviceResponse) { + ByteArrayInputStream is = new ByteArrayInputStream(serviceResponse + .getBytes()); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + UserDetails details = new UserDetails(); + String line = null, lastAttrKeyRead = null; + + try { + while ((line = br.readLine()) != null) { + String key, val; + if (line.startsWith(USER_DETAILS_ROLE)) { + // can't parse by splitting, parse by using substring + key = line.substring(0, USER_DETAILS_ROLE.length()); + val = line.substring(USER_DETAILS_ROLE.length() + 1); + } else { + String[] lineToks = line.split("="); + key = lineToks[0]; + val = lineToks[1]; + } + + if (key.equals(USER_DETAILS_TOKEN)) { + details.setToken(val); + } else if (key.equals(USER_DETAILS_ROLE)) { + details.getRoles().add(val); + } else if (key.equals(USER_DETAILS_ATTR_NAME)) { + lastAttrKeyRead = val; + } else if (key.equals(USER_DETAILS_ATTR_VALUE)) { + details.getAttributes().addMetadata(lastAttrKeyRead, val); + } + } + } catch (IOException e) { + LOG.log(Level.SEVERE, e.getMessage()); + LOG.log(Level.WARNING, "Error reading service response line: [" + line + + "]: Message: " + e.getMessage()); + } finally { + try { + is.close(); + } catch (Exception ignore) { + } + + try { + br.close(); + } catch (Exception ignore) { + } + + } + + return details; + } + + public static void main(String[] args) throws IOException, SingleSignOnException { + String usage = "SSOProxy [args]\n\n" + "Where cmd is one of:\n" + + "authenticate \n" + "identity \n" + + "attributes \nlogout \n"; + + if (args.length < 2 || args.length > 3) { + System.err.println(usage); + System.exit(1); + } + + String cmd = args[0]; + SSOProxy sso = new SSOProxy(); + if (cmd.equals(AUTH_COMMAND)) { + System.out.println(sso.authenticate(args[1], args[2])); + } else if (cmd.equals(IDENTITY_COMMAND)) { + System.out.println(sso.readIdentity(args[1], args[2])); + } else if (cmd.equals(ATTRIBUTES_COMMAND)) { + System.out.println(sso.getUserAttributes(args[1])); + } else if (cmd.equals(LOGOUT_COMMAND)) { + sso.logout(args[1]); + } + + } + +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SingleSignOnException.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SingleSignOnException.java b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SingleSignOnException.java new file mode 100644 index 0000000..bed65e7 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/SingleSignOnException.java @@ -0,0 +1,11 @@ +package org.apache.oodt.security.sso.opensso; + +/** + * Created by bugg on 27/10/15. + */ +public class SingleSignOnException extends Exception { + + public SingleSignOnException(String message) { + super(message); + } +} http://git-wip-us.apache.org/repos/asf/oodt/blob/f1e5bed6/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/UserDetails.java ---------------------------------------------------------------------- diff --git a/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/UserDetails.java b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/UserDetails.java new file mode 100755 index 0000000..ae442b1 --- /dev/null +++ b/curator/services/src/main/java/org/apache/oodt/security/sso/opensso/UserDetails.java @@ -0,0 +1,97 @@ +/** + * 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.oodt.security.sso.opensso; + +//OODT imports +import org.apache.oodt.cas.metadata.Metadata; + +//JDK imports +import java.util.List; +import java.util.Vector; + +/** + * + * The response from a query to {@link SSOMetKeys#IDENTITY_ATTRIBUTES_ENDPOINT}. + * + * @author mattmann + * @version $Revision$ + * + */ +public class UserDetails { + + private String token; + + private List roles; + + private Metadata attributes; + + public UserDetails() { + this.token = null; + this.roles = new Vector(); + this.attributes = new Metadata(); + } + + /** + * @return the token + */ + public String getToken() { + return token; + } + + /** + * @param token + * the token to set + */ + public void setToken(String token) { + this.token = token; + } + + /** + * @return the roles + */ + public List getRoles() { + return roles; + } + + /** + * @param roles + * the roles to set + */ + public void setRoles(List roles) { + this.roles = roles; + } + + /** + * @return the attributes + */ + public Metadata getAttributes() { + return attributes; + } + + /** + * @param attributes + * the attributes to set + */ + public void setAttributes(Metadata attributes) { + this.attributes = attributes; + } + + public String toString() { + return "[token=" + this.token + ",roles=" + this.roles + ",attributes=" + this.attributes.getMap() + "]"; + } +}