You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2013/12/25 14:44:10 UTC
svn commit: r1553380 - in /chemistry/opencmis/trunk:
chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/
chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemi...
Author: fmui
Date: Wed Dec 25 13:44:09 2013
New Revision: 1553380
URL: http://svn.apache.org/r1553380
Log:
added simple OAuth authentication provider
Added:
chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java
chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/AbstractAuthenticationProvider.java
chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/SessionFactoryImpl.java
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java
Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java?rev=1553380&r1=1553379&r2=1553380&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/SessionParameterMap.java Wed Dec 25 13:44:09 2013
@@ -247,6 +247,20 @@ public class SessionParameterMap extends
}
/**
+ * Sets bearer token.
+ *
+ * @param token
+ * the bearer token
+ */
+ public void setBearerToken(String token) {
+ if (token == null) {
+ remove(SessionParameter.BREARER_ACCESS_TOKEN);
+ } else {
+ put(SessionParameter.BREARER_ACCESS_TOKEN, token);
+ }
+ }
+
+ /**
* Turns all authentication off if the standard authentication provider is
* used.
*/
@@ -325,6 +339,26 @@ public class SessionParameterMap extends
}
/**
+ * Turns OAuth 2.0 bearer token authentication on and basic authentication
+ * and UsernameToken authentication off.
+ *
+ * @param token
+ * the bearer token
+ */
+ public void setOAuthBearerTokenAuthentication(String token) {
+ if (token == null) {
+ throw new IllegalArgumentException("Token must be set!");
+ }
+
+ setBearerToken(token);
+
+ put(SessionParameter.AUTH_HTTP_BASIC, false);
+ put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
+ put(SessionParameter.AUTH_OAUTH_BEARER, true);
+ put(SessionParameter.BREARER_ACCESS_TOKEN, token);
+ }
+
+ /**
* Sets the locale of the session.
*
* @param locale
Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/AbstractAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/AbstractAuthenticationProvider.java?rev=1553380&r1=1553379&r2=1553380&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/AbstractAuthenticationProvider.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/AbstractAuthenticationProvider.java Wed Dec 25 13:44:09 2013
@@ -108,7 +108,7 @@ public abstract class AbstractAuthentica
* @return the bearer token or {@code null} if the token is not set
*/
protected String getBearerToken() {
- Object tokenObject = getSession().get(SessionParameter.BREARER_TOKEN);
+ Object tokenObject = getSession().get(SessionParameter.BREARER_ACCESS_TOKEN);
if (tokenObject instanceof String) {
return (String) tokenObject;
}
Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java?rev=1553380&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-bindings/src/main/java/org/apache/chemistry/opencmis/client/bindings/spi/OAuthAuthenticationProvider.java Wed Dec 25 13:44:09 2013
@@ -0,0 +1,274 @@
+/*
+ * 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.chemistry.opencmis.client.bindings.spi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.chemistry.opencmis.client.bindings.impl.ClientVersion;
+import org.apache.chemistry.opencmis.commons.SessionParameter;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
+import org.apache.chemistry.opencmis.commons.impl.IOUtils;
+import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
+import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * OAuth Authentication Provider.
+ */
+public class OAuthAuthenticationProvider extends StandardAuthenticationProvider {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OAuthAuthenticationProvider.class);
+
+ private static final long serialVersionUID = 1L;
+
+ private String accessToken;
+ private String refreshToken;
+ private long expiresTimestamp;
+
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+ @Override
+ public Map<String, List<String>> getHTTPHeaders(String url) {
+ Map<String, List<String>> headers = super.getHTTPHeaders(url);
+ if (headers == null) {
+ headers = new HashMap<String, List<String>>();
+ }
+
+ headers.put("Authorization", Collections.singletonList("Bearer " + getToken()));
+
+ return headers;
+ }
+
+ /**
+ * Gets the access token. If no access token is present or the access token
+ * expired, a new token is requested.
+ *
+ * @return the access token
+ */
+ protected String getToken() {
+ lock.writeLock().lock();
+ try {
+ if (accessToken == null) {
+ requestToken();
+ } else if (System.currentTimeMillis() >= expiresTimestamp) {
+ refreshToken();
+ }
+ return accessToken;
+ } catch (CmisConnectionException ce) {
+ throw ce;
+ } catch (Exception e) {
+ throw new CmisConnectionException("Cannot get OAuth access token: " + e.getMessage(), e);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ private void requestToken() throws IOException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Request new OAuth access token.");
+ }
+
+ makeRequest(false);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Access token: {} / Refresh token: {}", accessToken, refreshToken);
+ }
+ }
+
+ private void refreshToken() throws IOException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Refresh new OAuth access token.");
+ }
+
+ makeRequest(true);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Access token: {} / Refresh token: {}", accessToken, refreshToken);
+ }
+ }
+
+ private void makeRequest(boolean isRefresh) throws IOException {
+ Object tokenEndpoint = getSession().get(SessionParameter.OAUTH_TOKEN_ENDPOINT);
+ if (!(tokenEndpoint instanceof String)) {
+ throw new CmisConnectionException("Token endpoint not set!");
+ }
+
+ if (isRefresh && refreshToken == null) {
+ throw new CmisConnectionException("No refresh token!");
+ }
+
+ // request token
+ HttpURLConnection conn = (HttpURLConnection) (new URL(tokenEndpoint.toString())).openConnection();
+ conn.setRequestMethod("POST");
+ conn.setDoInput(true);
+ conn.setDoOutput(true);
+ conn.setAllowUserInteraction(false);
+ conn.setUseCaches(false);
+ conn.setRequestProperty("User-Agent", ClientVersion.OPENCMIS_CLIENT);
+ conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
+
+ // compile request
+ Writer writer = new OutputStreamWriter(conn.getOutputStream(), IOUtils.UTF8);
+
+ if (isRefresh) {
+ writer.write("grant_type=refresh_token");
+
+ writer.write("&refresh_token=");
+ writer.write(IOUtils.encodeURL(refreshToken));
+ } else {
+ writer.write("grant_type=authorization_code");
+
+ Object code = getSession().get(SessionParameter.OAUTH_CODE);
+ if (code != null) {
+ writer.write("&code=");
+ writer.write(IOUtils.encodeURL(code.toString()));
+ }
+
+ Object redirectUri = getSession().get(SessionParameter.OAUTH_REDIRECT_URI);
+ if (redirectUri != null) {
+ writer.write("&redirect_uri=");
+ writer.write(IOUtils.encodeURL(redirectUri.toString()));
+ }
+ }
+
+ Object clientId = getSession().get(SessionParameter.OAUTH_CLIENT_ID);
+ if (clientId != null) {
+ writer.write("&client_id=");
+ writer.write(IOUtils.encodeURL(clientId.toString()));
+ }
+
+ Object clientSecret = getSession().get(SessionParameter.OAUTH_CLIENT_SECRET);
+ if (clientSecret != null) {
+ writer.write("&client_secret=");
+ writer.write(IOUtils.encodeURL(clientSecret.toString()));
+ }
+
+ writer.flush();
+
+ // connect
+ conn.connect();
+
+ // check success
+ if (conn.getResponseCode() != 200) {
+ JSONObject jsonResponse = parseResponse(conn);
+ Object error = jsonResponse.get("error");
+ Object description = jsonResponse.get("error_description");
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("OAuth token request failed: {}", jsonResponse.toJSONString());
+ }
+
+ throw new CmisConnectionException("OAuth token request failed" + (error == null ? "" : ": " + error)
+ + (description == null ? "" : ": " + description));
+ }
+
+ // parse response
+ JSONObject jsonResponse = parseResponse(conn);
+
+ Object tokenType = jsonResponse.get("token_type");
+ if (!(tokenType instanceof String) || !"bearer".equalsIgnoreCase((String) tokenType)) {
+ throw new CmisConnectionException("Unsupported OAuth token type: " + tokenType);
+ }
+
+ Object jsonAccessToken = jsonResponse.get("access_token");
+ if (!(jsonAccessToken instanceof String)) {
+ throw new CmisConnectionException("Invalid OAuth access token!");
+ }
+
+ Object jsonRefreshToken = jsonResponse.get("refresh_token");
+ if (jsonRefreshToken != null && !(jsonRefreshToken instanceof String)) {
+ throw new CmisConnectionException("Invalid OAuth refresh token!");
+ }
+
+ Object jsonExpiresIn = jsonResponse.get("expires_in");
+ if (jsonExpiresIn != null && !(jsonExpiresIn instanceof Number)) {
+ throw new CmisConnectionException("Invalid OAuth expires in value!");
+ }
+
+ accessToken = jsonAccessToken.toString();
+ refreshToken = (jsonRefreshToken == null ? null : jsonRefreshToken.toString());
+ expiresTimestamp = (jsonExpiresIn == null ? 3600 : ((Number) jsonExpiresIn).longValue()) * 1000
+ + System.currentTimeMillis();
+ }
+
+ private JSONObject parseResponse(HttpURLConnection conn) {
+ Reader reader = null;
+ try {
+ InputStream stream = null;
+
+ int respCode = conn.getResponseCode();
+ if (respCode >= 200 && respCode < 300) {
+ stream = conn.getInputStream();
+ } else {
+ stream = conn.getErrorStream();
+ }
+ if (stream == null) {
+ throw new CmisConnectionException("Invalid OAuth token response!");
+ }
+
+ reader = new InputStreamReader(stream, extractCharset(conn));
+ JSONParser parser = new JSONParser();
+ Object response = parser.parse(reader);
+
+ if (!(response instanceof JSONObject)) {
+ throw new CmisConnectionException("Invalid OAuth token response!");
+ }
+
+ return (JSONObject) response;
+ } catch (CmisConnectionException ce) {
+ throw ce;
+ } catch (Exception pe) {
+ throw new CmisConnectionException("Parsing the OAuth token response failed: " + pe.getMessage(), pe);
+ } finally {
+ IOUtils.consumeAndClose(reader);
+ }
+ }
+
+ private String extractCharset(HttpURLConnection conn) {
+ String charset = IOUtils.UTF8;
+
+ String contentType = conn.getContentType();
+ if (contentType != null) {
+ String[] parts = contentType.split(";");
+ for (int i = 1; i < parts.length; i++) {
+ String part = parts[i].trim().toLowerCase();
+ if (part.startsWith("charset")) {
+ int x = part.indexOf('=');
+ charset = part.substring(x + 1).trim();
+ break;
+ }
+ }
+ }
+
+ return charset;
+ }
+}
Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/SessionFactoryImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/SessionFactoryImpl.java?rev=1553380&r1=1553379&r2=1553380&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/SessionFactoryImpl.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/SessionFactoryImpl.java Wed Dec 25 13:44:09 2013
@@ -113,7 +113,8 @@ public class SessionFactoryImpl implemen
List<Repository> result = new ArrayList<Repository>();
for (RepositoryInfo data : repositoryInfos) {
- result.add(new RepositoryImpl(data, parameters, this, objectFactory, authenticationProvider, cache));
+ result.add(new RepositoryImpl(data, parameters, this, objectFactory, binding.getAuthenticationProvider(),
+ cache));
}
return result;
Modified: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java?rev=1553380&r1=1553379&r2=1553380&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-api/src/main/java/org/apache/chemistry/opencmis/commons/SessionParameter.java Wed Dec 25 13:44:09 2013
@@ -500,7 +500,6 @@ public final class SessionParameter {
// ---- general parameter ----
public static final String USER = "org.apache.chemistry.opencmis.user";
public static final String PASSWORD = "org.apache.chemistry.opencmis.password";
- public static final String BREARER_TOKEN = "org.apache.chemistry.opencmis.oauth.brearertoken";
// --- binding parameter ----
/** Predefined binding types (see {@code BindingType}). */
@@ -553,6 +552,8 @@ public final class SessionParameter {
/** Factory class name for the local binding. */
public static final String LOCAL_FACTORY = "org.apache.chemistry.opencmis.binding.local.classname";
+ // --- authentication ---
+
/** Class name of the authentication provider. */
public static final String AUTHENTICATION_PROVIDER_CLASS = "org.apache.chemistry.opencmis.binding.auth.classname";
@@ -574,6 +575,16 @@ public final class SessionParameter {
*/
public static final String AUTH_SOAP_USERNAMETOKEN = "org.apache.chemistry.opencmis.binding.auth.soap.usernametoken";
+ // --- OAuth ---
+
+ public static final String OAUTH_CLIENT_ID = "org.apache.chemistry.opencmis.oauth.clientId";
+ public static final String OAUTH_CLIENT_SECRET = "org.apache.chemistry.opencmis.oauth.clientSecret";
+ public static final String OAUTH_CODE = "org.apache.chemistry.opencmis.oauth.code";
+ public static final String OAUTH_TOKEN_ENDPOINT = "org.apache.chemistry.opencmis.oauth.tokenEndpoint";
+ public static final String OAUTH_REDIRECT_URI = "org.apache.chemistry.opencmis.oauth.redirectUri";
+
+ public static final String BREARER_ACCESS_TOKEN = "org.apache.chemistry.opencmis.oauth.accessToken";
+
// --- connection ---
public static final String HTTP_INVOKER_CLASS = "org.apache.chemistry.opencmis.binding.httpinvoker.classname";