Author: ieb
Date: Fri Aug 16 11:31:25 2013
New Revision: 1514660
URL: http://svn.apache.org/r1514660
Log:
refactored to cover just request signing, ignoring responses signing.
Added:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacFilter.java
(with props)
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacService.java
(with props)
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacServiceImpl.java
(with props)
Removed:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/SealedResponse.java
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/SealingFilter.java
Added:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacFilter.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacFilter.java?rev=1514660&view=auto
==============================================================================
---
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacFilter.java
(added)
+++
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacFilter.java
Fri Aug 16 11:31:25 2013
@@ -0,0 +1,129 @@
+/*
+ * 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 SF 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.sling.sealed;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+
+@Service(value = Filter.class)
+@Component(immediate = true, metatype = true)
+@Properties(@Property(name = "path", value = "/sealed"))
+public class RequestHmacFilter implements Filter {
+
+ @Property(cardinality = Integer.MAX_VALUE)
+ private static final String PROP_PATTERNS = "sealed-paths";
+
+ private Pattern[] pathPatterns;
+
+ @Reference
+ private RequestHmacService sealer;
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Activate
+ public void activate(Map<String, Object> properties) {
+ pathPatterns = buildPatterns((String[]) properties.get(PROP_PATTERNS));
+ }
+
+ private Pattern[] buildPatterns(String[] patterns) {
+ if (patterns != null) {
+ Pattern[] p = new Pattern[patterns.length];
+ for (int i = 0; i < p.length; i++) {
+ p[i] = Pattern.compile(patterns[i]);
+ }
+ return p;
+ }
+ return new Pattern[0];
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
+ throws IOException, ServletException {
+ if (isSecure(request) && failsVerification(request)) {
+ ((HttpServletResponse)
response).sendError(HttpServletResponse.SC_FORBIDDEN,
+ "Untrusted request");
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ /**
+ *
+ * @param request
+ * @return false if the request passes verification.
+ * @throws IOException
+ */
+ private boolean failsVerification(ServletRequest request) throws
IOException {
+ if (request instanceof HttpServletRequest) {
+ HttpServletRequest hrequest = (HttpServletRequest) request;
+ return !sealer.verifyRequest(hrequest);
+ }
+ return false;
+ }
+
+ /**
+ * Should the request and response be secure and trusted ?
+ *
+ * @param request
+ * @return
+ */
+ private boolean isSecure(ServletRequest request) {
+ if (sealer.isConfigured() && request instanceof HttpServletRequest) {
+ return match(((HttpServletRequest) request).getRequestURI(),
pathPatterns);
+ }
+ return false;
+ }
+
+
+ /**
+ * return true if the test matches any of the patterns.
+ *
+ * @param test
+ * @param patterns
+ * @return
+ */
+ private boolean match(String test, Pattern[] patterns) {
+ for (Pattern urls : patterns) {
+ if (urls.matcher(test).find()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void destroy() {
+ }
+
+}
Propchange:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacService.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacService.java?rev=1514660&view=auto
==============================================================================
---
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacService.java
(added)
+++
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacService.java
Fri Aug 16 11:31:25 2013
@@ -0,0 +1,56 @@
+/*
+ * 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 SF 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.sling.sealed;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Provides
+ */
+public interface RequestHmacService {
+
+ String X_SIG_HEADER = "x-sig";
+
+
+ /**
+ * @return true of the sealer implementation is configured.
+ */
+ boolean isConfigured();
+
+ /**
+ * @param hrequest the request to verify.
+ * @return true if valid.
+ */
+ boolean verifyRequest(HttpServletRequest hrequest);
+
+ /**
+ * Get a request hmac header for a request URI, parameters and headers.
Clients should set a
+ * request header with the name contained in the constant X_SIG_HEADER
before sending the request.
+ * @param requestUri
+ * @param requestParams
+ * @param headers
+ * @return the request header that should be sent with the the request.
+ * @throws UnsupportedEncodingException
+ */
+ String getRequestHeader(String requestUri, Map<String, String[]>
requestParams,
+ Map<String, String> headers) throws UnsupportedEncodingException;
+
+}
Propchange:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacService.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacServiceImpl.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacServiceImpl.java?rev=1514660&view=auto
==============================================================================
---
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacServiceImpl.java
(added)
+++
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacServiceImpl.java
Fri Aug 16 11:31:25 2013
@@ -0,0 +1,174 @@
+/*
+ * 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 SF 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.sling.sealed;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+
+@Component(immediate=true, metatype=true)
+@Service(value=RequestHmacService.class)
+public class RequestHmacServiceImpl implements RequestHmacService {
+
+ private static final String HMAC_ALG = "HmacSHA256";
+
+ @Property(cardinality= Integer.MAX_VALUE)
+ private static final String PROP_HEADERNAMES = "sealed-headers";
+
+ @Property
+ private static final String PROP_SHARED_KEY = "shared-key";
+
+
+ private String[] headerNames;
+
+ private Key key;
+
+
+
+ @Activate
+ public void activate(Map<String, Object> properties) {
+ headerNames = buildHeaderNames((String[])
properties.get(PROP_HEADERNAMES));
+ key = buildKey((String) properties.get(PROP_SHARED_KEY));
+ }
+
+
+ public boolean verifyRequest(HttpServletRequest hrequest) {
+ try {
+ return verifyHmac(buildRequestMessage(hrequest),
hrequest.getHeader(X_SIG_HEADER));
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Get a hmac from a captured response.
+ * @param byteOutputStream
+ * @param headers
+ * @return
+ * @throws UnsupportedEncodingException
+ */
+ public String getRequestHeader(String requestUri, Map<String, String[]>
requestParams, Map<String, String> headers)
+ throws UnsupportedEncodingException {
+ return doMac(buildRequestMesssage(requestUri, requestParams, headers));
+ }
+
+ private String buildRequestMesssage(String uri, Map<String, String[]>
params, Map<String, String> headers)
+ throws UnsupportedEncodingException {
+ StringBuilder message = new StringBuilder(uri);
+ for (String headerName : headerNames) {
+ message.append(headers.get(headerName));
+ }
+ List<String> orderedNames = new ArrayList<String>(params.keySet());
+ Collections.sort(orderedNames);
+ for (String n : orderedNames) {
+ message.append(n).append(Arrays.toString(params.get(n)));
+ }
+ return message.toString();
+ }
+
+ public boolean isConfigured() {
+ return (key != null);
+ }
+
+ /**
+ * Build a message from the request
+ *
+ * @param request
+ * @return
+ * @throws IOException
+ */
+ private String buildRequestMessage(HttpServletRequest request) throws
IOException {
+ Map<String, String> headers = new HashMap<String, String>();
+ for (String headerName : headerNames) {
+ String v = request.getHeader(headerName);
+ headers.put(headerName, v);
+ }
+ return buildRequestMesssage(request.getRequestURI(),
request.getParameterMap(), headers);
+ }
+
+ /**
+ * verify a message against a hmac.
+ *
+ * @param message the message
+ * @param hmac the hmac
+ * @return true if the message hasn't been tampered with and the hmac was
+ * created with the same key.
+ */
+ private boolean verifyHmac(String message, String hmac) {
+ String newMac = doMac(message);
+ return (hmac != null && newMac != null && !hmac.equals(newMac));
+ }
+
+ /**
+ * Perform a hmac on a message.
+ *
+ * @param message the message
+ * @return the hmac of the message or null if the hmac cant be computed.
+ */
+ private String doMac(String message) {
+ try {
+ Mac mac = Mac.getInstance(HMAC_ALG);
+ mac.init(key);
+ return new
String(Base64.encodeBase64(mac.doFinal(message.getBytes("UTF-8"))), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ } catch (IllegalStateException e) {
+ } catch (NoSuchAlgorithmException e) {
+ } catch (InvalidKeyException e) {
+ }
+ return null;
+ }
+
+ private Key buildKey(String sharedKey) {
+ if ( sharedKey != null ) {
+ return new SecretKeySpec(sharedKey.getBytes(), HMAC_ALG);
+ }
+ return null;
+
+ }
+
+
+ private String[] buildHeaderNames(String[] names) {
+ if ( names != null ) {
+ return names;
+ }
+ return new String[0];
+ }
+
+
+
+
+
+}
Propchange:
sling/whiteboard/ieb/sealed/src/main/java/org/apache/sling/sealed/RequestHmacServiceImpl.java
------------------------------------------------------------------------------
svn:eol-style = native