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 608B0200C5C for ; Wed, 5 Apr 2017 14:20:34 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 5CE6B160B94; Wed, 5 Apr 2017 12:20:34 +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 7237E160B91 for ; Wed, 5 Apr 2017 14:20:33 +0200 (CEST) Received: (qmail 61892 invoked by uid 500); 5 Apr 2017 12:20:32 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 61878 invoked by uid 99); 5 Apr 2017 12:20: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; Wed, 05 Apr 2017 12:20:32 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 82BFADFC8E; Wed, 5 Apr 2017 12:20:32 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: coheigea@apache.org To: commits@cxf.apache.org Date: Wed, 05 Apr 2017 12:20:32 -0000 Message-Id: <6877272a75fe404bacb62d4ef0a9225a@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [1/4] cxf git commit: Refactor how we extract "IDs" from delegation tokens when used for caching archived-at: Wed, 05 Apr 2017 12:20:34 -0000 Repository: cxf Updated Branches: refs/heads/3.0.x-fixes 2b56bf00a -> 750b01a6e Refactor how we extract "IDs" from delegation tokens when used for caching # Conflicts: # rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/262d17c5 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/262d17c5 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/262d17c5 Branch: refs/heads/3.0.x-fixes Commit: 262d17c5a3588acc28ff2a2ae5dc5280b35e6fb2 Parents: 2b56bf0 Author: Colm O hEigeartaigh Authored: Wed Apr 5 11:01:21 2017 +0100 Committer: Colm O hEigeartaigh Committed: Wed Apr 5 12:51:09 2017 +0100 ---------------------------------------------------------------------- .../security/trust/DefaultSTSTokenCacher.java | 210 +++++++++++++++++++ 1 file changed, 210 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/262d17c5/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java ---------------------------------------------------------------------- diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java new file mode 100644 index 0000000..c2699fc --- /dev/null +++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/trust/DefaultSTSTokenCacher.java @@ -0,0 +1,210 @@ +/** + * 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.ws.security.trust; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import org.w3c.dom.Element; + +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.message.Message; +import org.apache.cxf.rt.security.utils.SecurityUtils; +import org.apache.cxf.ws.security.SecurityConstants; +import org.apache.cxf.ws.security.tokenstore.SecurityToken; +import org.apache.cxf.ws.security.tokenstore.TokenStore; +import org.apache.cxf.ws.security.tokenstore.TokenStoreUtils; +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.SamlAssertionWrapper; +import org.apache.wss4j.common.util.XMLUtils; +import org.apache.wss4j.dom.WSConstants; + +public class DefaultSTSTokenCacher implements STSTokenCacher { + + public SecurityToken retrieveToken(Message message) { + boolean cacheIssuedToken = + SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, + message, + true); + SecurityToken tok = null; + if (cacheIssuedToken) { + tok = (SecurityToken)message.getContextualProperty(SecurityConstants.TOKEN); + if (tok == null) { + String tokId = (String)message.getContextualProperty(SecurityConstants.TOKEN_ID); + if (tokId != null) { + tok = TokenStoreUtils.getTokenStore(message).getToken(tokId); + } + } + } else { + tok = (SecurityToken)message.get(SecurityConstants.TOKEN); + if (tok == null) { + String tokId = (String)message.get(SecurityConstants.TOKEN_ID); + if (tokId != null) { + tok = TokenStoreUtils.getTokenStore(message).getToken(tokId); + } + } + } + return tok; + } + + public SecurityToken retrieveToken(Message message, Element delegationToken, String cacheKey) { + if (delegationToken == null) { + return null; + } + TokenStore tokenStore = TokenStoreUtils.getTokenStore(message); + + // See if the token corresponding to the delegation Token is stored in the cache + // and if it points to an issued token + String id = getIdFromToken(delegationToken); + SecurityToken cachedToken = tokenStore.getToken(id); + if (cachedToken != null) { + Map properties = cachedToken.getProperties(); + if (properties != null && properties.containsKey(cacheKey)) { + String associatedToken = (String)properties.get(cacheKey); + SecurityToken issuedToken = tokenStore.getToken(associatedToken); + if (issuedToken != null) { + return issuedToken; + } + } + } + + return null; + } + + public void storeToken(Message message, SecurityToken securityToken) { + boolean cacheIssuedToken = + SecurityUtils.getSecurityPropertyBoolean(SecurityConstants.CACHE_ISSUED_TOKEN_IN_ENDPOINT, + message, + true) + && !isOneTimeUse(securityToken); + if (cacheIssuedToken) { + message.getExchange().getEndpoint().put(SecurityConstants.TOKEN, securityToken); + message.getExchange().put(SecurityConstants.TOKEN, securityToken); + message.put(SecurityConstants.TOKEN_ELEMENT, securityToken.getToken()); + message.getExchange().put(SecurityConstants.TOKEN_ID, securityToken.getId()); + message.getExchange().getEndpoint().put(SecurityConstants.TOKEN_ID, + securityToken.getId()); + } else { + message.put(SecurityConstants.TOKEN, securityToken); + message.put(SecurityConstants.TOKEN_ID, securityToken.getId()); + message.put(SecurityConstants.TOKEN_ELEMENT, securityToken.getToken()); + } + // ? + TokenStoreUtils.getTokenStore(message).add(securityToken); + } + + public void storeToken(Message message, Element delegationToken, String secTokenId, String cacheKey) { + if (secTokenId == null || delegationToken == null) { + return; + } + + TokenStore tokenStore = TokenStoreUtils.getTokenStore(message); + + String id = getIdFromToken(delegationToken); + SecurityToken cachedToken = tokenStore.getToken(id); + if (cachedToken == null) { + cachedToken = new SecurityToken(id); + cachedToken.setToken(delegationToken); + } + Map properties = cachedToken.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + cachedToken.setProperties(properties); + } + properties.put(cacheKey, secTokenId); + tokenStore.add(cachedToken); + } + + public void removeToken(Message message, SecurityToken securityToken) { + // Remove token from cache + message.getExchange().getEndpoint().remove(SecurityConstants.TOKEN); + message.getExchange().getEndpoint().remove(SecurityConstants.TOKEN_ID); + message.getExchange().remove(SecurityConstants.TOKEN_ID); + message.getExchange().remove(SecurityConstants.TOKEN); + if (securityToken != null) { + TokenStoreUtils.getTokenStore(message).remove(securityToken.getId()); + } + } + + // Check to see if the received token is a SAML2 Token with "OneTimeUse" set. If so, + // it should not be cached on the endpoint, but only on the message. + private static boolean isOneTimeUse(SecurityToken issuedToken) { + Element token = issuedToken.getToken(); + if (token != null && "Assertion".equals(token.getLocalName()) + && WSConstants.SAML2_NS.equals(token.getNamespaceURI())) { + try { + SamlAssertionWrapper assertion = new SamlAssertionWrapper(token); + + if (assertion.getSaml2().getConditions() != null + && assertion.getSaml2().getConditions().getOneTimeUse() != null) { + return true; + } + } catch (WSSecurityException ex) { + throw new Fault(ex); + } + } + + return false; + } + + // Get an id from the token that is unique to that token + private static String getIdFromToken(Element token) { + if (token != null) { + // For SAML tokens get the ID/AssertionID + if ("Assertion".equals(token.getLocalName()) + && WSConstants.SAML2_NS.equals(token.getNamespaceURI())) { + return token.getAttributeNS(null, "ID"); + } else if ("Assertion".equals(token.getLocalName()) + && WSConstants.SAML_NS.equals(token.getNamespaceURI())) { + return token.getAttributeNS(null, "AssertionID"); + } + + // For UsernameTokens get the username + if (WSConstants.USERNAME_TOKEN_LN.equals(token.getLocalName()) + && WSConstants.WSSE_NS.equals(token.getNamespaceURI())) { + Element usernameElement = + XMLUtils.getDirectChildElement(token, WSConstants.USERNAME_LN, WSConstants.WSSE_NS); + if (usernameElement != null) { + return XMLUtils.getElementText(usernameElement); + } + } + + // For BinarySecurityTokens take the hash of the value + if (WSConstants.BINARY_TOKEN_LN.equals(token.getLocalName()) + && WSConstants.WSSE_NS.equals(token.getNamespaceURI())) { + String text = XMLUtils.getElementText(token); + if (text != null && !"".equals(text)) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] bytes = digest.digest(text.getBytes()); + return Base64.getMimeEncoder().encodeToString(bytes); + } catch (NoSuchAlgorithmException e) { + // SHA-256 must be supported so not going to happen... + } + } + } + } + return ""; + } + +} \ No newline at end of file