Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add some unit test for dubbo-auth #5547

Merged
merged 3 commits into from
Feb 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,50 +17,54 @@
package org.apache.dubbo.auth;

import org.apache.dubbo.auth.exception.AccessKeyNotFoundException;
import org.apache.dubbo.auth.exception.RpcAuthenticationException;
import org.apache.dubbo.auth.model.AccessKeyPair;
import org.apache.dubbo.auth.spi.AccessKeyStorage;
import org.apache.dubbo.auth.spi.AuthenticationHelper;
import org.apache.dubbo.auth.spi.Authenticator;
import org.apache.dubbo.auth.utils.SignatureUtils;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invocation;

public class AccessKeyAuthenticationHelper implements AuthenticationHelper {
public class AccessKeyAuthenticator implements Authenticator {
@Override
public void signForRequest(Invocation invocation, URL url) {
public void sign(Invocation invocation, URL url) {
String currentTime = String.valueOf(System.currentTimeMillis());
String consumer = url.getParameter(CommonConstants.APPLICATION_KEY);
AccessKeyPair accessKeyPair = getAccessKeyPair(invocation, url);
invocation.setAttachment(Constants.SIGNATURE_STRING_FORMAT, getSignature(url, invocation, accessKeyPair.getSecretKey(), currentTime));
invocation.setAttachment(Constants.REQUEST_SIGNATURE_KEY, getSignature(url, invocation, accessKeyPair.getSecretKey(), currentTime));
invocation.setAttachment(Constants.REQUEST_TIMESTAMP_KEY, currentTime);
invocation.setAttachment(Constants.AK_KEY, accessKeyPair.getAccessKey());
invocation.setAttachment(CommonConstants.CONSUMER, consumer);
}

@Override
public boolean authenticateRequest(Invocation invocation, URL url) {
public void authenticate(Invocation invocation, URL url) throws RpcAuthenticationException {
String accessKeyId = String.valueOf(invocation.getAttachment(Constants.AK_KEY));
String requestTimestamp = String.valueOf(invocation.getAttachment(Constants.REQUEST_TIMESTAMP_KEY));
String originSignature = String.valueOf(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY));
String consumer = String.valueOf(invocation.getAttachment(CommonConstants.CONSUMER));

if (StringUtils.isEmpty(accessKeyId) || StringUtils.isEmpty(consumer)
|| StringUtils.isEmpty(requestTimestamp) || StringUtils.isEmpty(originSignature)) {
throw new RuntimeException("Auth failed, maybe consumer not enable the auth");
throw new RpcAuthenticationException("Failed to authenticate, maybe consumer not enable the auth");
}
AccessKeyPair accessKeyPair = null;
try {
accessKeyPair = getAccessKeyPair(invocation, url);
} catch (Exception e) {
throw new RpcAuthenticationException("Failed to authenticate , can't load the accessKeyPair", e);
}
AccessKeyPair accessKeyPair = getAccessKeyPair(invocation, url);

String computeSignature = getSignature(url, invocation, accessKeyPair.getSecretKey(), requestTimestamp);
boolean success = computeSignature.equals(originSignature);
if (!success) {
throw new RuntimeException("Auth failed, signature is not correct");
throw new RpcAuthenticationException("Failed to authenticate, signature is not correct");
}
return success;
}


AccessKeyPair getAccessKeyPair(Invocation invocation, URL url) {
AccessKeyStorage accessKeyStorage = ExtensionLoader.getExtensionLoader(AccessKeyStorage.class)
.getExtension(url.getParameter(Constants.ACCESS_KEY_STORAGE_KEY, Constants.DEFAULT_ACCESS_KEY_STORAGE));
Expand All @@ -78,7 +82,7 @@ AccessKeyPair getAccessKeyPair(Invocation invocation, URL url) {
}

String getSignature(URL url, Invocation invocation, String secrectKey, String time) {
boolean parameterEncrypt = url.getParameter(Constants.PARAMTER_ENCRYPT_ENABLE_KEY, false);
boolean parameterEncrypt = url.getParameter(Constants.PARAMTER_SIGNATURE_ENABLE_KEY, false);
String signature;
String requestString = String.format(Constants.SIGNATURE_STRING_FORMAT,
url.getColonSeparatedKey(), invocation.getMethodName(), secrectKey, time);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@


public interface Constants {
String REFERENCE_AUTH = "reference.auth";

String SERVICE_AUTH = "service.auth";
String SERVICE_AUTH = "auth";

String AUTH_HELPER = "auth.helper";
String AUTHENTICATOR = "authenticator";

String DEFAULT_AUTH_HELPER = "accesskey";
String DEFAULT_AUTHENTICATOR = "accesskey";

String DEFAULT_ACCESS_KEY_STORAGE = "urlstorage";

Expand All @@ -42,5 +41,5 @@ public interface Constants {

String SIGNATURE_STRING_FORMAT = "%s#%s#%s#%s";

String PARAMTER_ENCRYPT_ENABLE_KEY = "paramater.sign";
String PARAMTER_SIGNATURE_ENABLE_KEY = "param.sign";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.dubbo.auth.exception;


public class RpcAuthenticationException extends Exception {
public RpcAuthenticationException() {
}

public RpcAuthenticationException(String message) {
super(message);
}

public RpcAuthenticationException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package org.apache.dubbo.auth.filter;

import org.apache.dubbo.auth.Constants;
import org.apache.dubbo.auth.spi.AuthenticationHelper;
import org.apache.dubbo.auth.spi.Authenticator;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
Expand All @@ -39,11 +39,11 @@ public class ConsumerSignFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
URL url = invoker.getUrl();
boolean shouldAuth = url.getParameter(Constants.REFERENCE_AUTH, false);
boolean shouldAuth = url.getParameter(Constants.SERVICE_AUTH, false);
if (shouldAuth) {
AuthenticationHelper authenticationHelper = ExtensionLoader.getExtensionLoader(AuthenticationHelper.class)
.getExtension(url.getParameter(Constants.AUTH_HELPER, Constants.DEFAULT_AUTH_HELPER));
authenticationHelper.signForRequest(invocation, url);
Authenticator authenticator = ExtensionLoader.getExtensionLoader(Authenticator.class)
.getExtension(url.getParameter(Constants.AUTHENTICATOR, Constants.DEFAULT_AUTHENTICATOR));
authenticator.sign(invocation, url);
}
return invoker.invoke(invocation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
*/
package org.apache.dubbo.auth.filter;

import org.apache.dubbo.auth.spi.AuthenticationHelper;
import org.apache.dubbo.auth.Constants;
import org.apache.dubbo.auth.spi.Authenticator;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.auth.Constants;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
Expand All @@ -37,18 +37,12 @@ public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcExcept
URL url = invoker.getUrl();
boolean shouldAuth = url.getParameter(Constants.SERVICE_AUTH, false);
if (shouldAuth) {
AuthenticationHelper authenticationHelper = ExtensionLoader.getExtensionLoader(AuthenticationHelper.class)
.getExtension(url.getParameter(Constants.AUTH_HELPER, Constants.DEFAULT_AUTH_HELPER));
boolean authResult = false;
Authenticator authenticator = ExtensionLoader.getExtensionLoader(Authenticator.class)
.getExtension(url.getParameter(Constants.AUTHENTICATOR, Constants.DEFAULT_AUTHENTICATOR));
try {
authResult = authenticationHelper.authenticateRequest(invocation, url);
if (!authResult) {
SecurityException securityException = new SecurityException("Authenticate Request failed");
return AsyncRpcResult.newDefaultAsyncResult(securityException, invocation);
}
authenticator.authenticate(invocation, url);
} catch (Exception e) {
SecurityException securityException = new SecurityException("Authenticate Request failed,", e);
return AsyncRpcResult.newDefaultAsyncResult(securityException, invocation);
return AsyncRpcResult.newDefaultAsyncResult(e, invocation);
}
}
return invoker.invoke(invocation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,28 @@
package org.apache.dubbo.auth.spi;


import org.apache.dubbo.auth.exception.RpcAuthenticationException;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.rpc.Invocation;

@SPI("accessKey")
public interface AuthenticationHelper {
public interface Authenticator {

/**
* give a sign to request
*
* @param invocation
* @param url
*/
void signForRequest(Invocation invocation, URL url);
void sign(Invocation invocation, URL url);


/**
* verify the signature of the request is valid or not
*
* @param invocation
* @param url
* @return true if the signature is valid
* @throws RpcAuthenticationException when failed to authenticate current invocation
*/
boolean authenticateRequest(Invocation invocation, URL url);
void authenticate(Invocation invocation, URL url) throws RpcAuthenticationException;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
accesskey=org.apache.dubbo.auth.AccessKeyAuthenticator
Original file line number Diff line number Diff line change
@@ -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.dubbo.auth;

import org.apache.dubbo.auth.exception.RpcAuthenticationException;
import org.apache.dubbo.auth.model.AccessKeyPair;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.RpcInvocation;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


class AccessKeyAuthenticatorTest {

@Test
void testSignForRequest() {
URL url = URL.valueOf("dubbo://10.10.10.10:2181")
.addParameter(Constants.ACCESS_KEY_ID_KEY, "ak")
.addParameter(CommonConstants.APPLICATION_KEY, "test")
.addParameter(Constants.SECRET_ACCESS_KEY_KEY, "sk");
Invocation invocation = new RpcInvocation();

AccessKeyAuthenticator helper = mock(AccessKeyAuthenticator.class);
doCallRealMethod().when(helper).sign(invocation, url);
when(helper.getSignature(eq(url), eq(invocation), eq("sk"), anyString())).thenReturn("dubbo");

AccessKeyPair accessKeyPair = mock(AccessKeyPair.class);
when(accessKeyPair.getSecretKey()).thenReturn("sk");
when(helper.getAccessKeyPair(invocation, url)).thenReturn(accessKeyPair);

helper.sign(invocation, url);
assertEquals(String.valueOf(invocation.getAttachment(CommonConstants.CONSUMER)), url.getParameter(CommonConstants.APPLICATION_KEY));
assertNotNull(invocation.getAttachments().get(Constants.REQUEST_SIGNATURE_KEY));
assertEquals(invocation.getAttachments().get(Constants.REQUEST_SIGNATURE_KEY), "dubbo");
}

@Test
void testAuthenticateRequest() throws RpcAuthenticationException {
URL url = URL.valueOf("dubbo://10.10.10.10:2181")
.addParameter(Constants.ACCESS_KEY_ID_KEY, "ak")
.addParameter(CommonConstants.APPLICATION_KEY, "test")
.addParameter(Constants.SECRET_ACCESS_KEY_KEY, "sk");
Invocation invocation = new RpcInvocation();
invocation.setAttachment(Constants.ACCESS_KEY_ID_KEY, "ak");
invocation.setAttachment(Constants.REQUEST_SIGNATURE_KEY, "dubbo");
invocation.setAttachment(Constants.REQUEST_TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
invocation.setAttachment(CommonConstants.CONSUMER, "test");

AccessKeyAuthenticator helper = mock(AccessKeyAuthenticator.class);
doCallRealMethod().when(helper).authenticate(invocation, url);
when(helper.getSignature(eq(url), eq(invocation), eq("sk"), anyString())).thenReturn("dubbo");

AccessKeyPair accessKeyPair = mock(AccessKeyPair.class);
when(accessKeyPair.getSecretKey()).thenReturn("sk");
when(helper.getAccessKeyPair(invocation, url)).thenReturn(accessKeyPair);

assertDoesNotThrow(() -> helper.authenticate(invocation, url));
}

@Test
void testAuthenticateRequestNoSignature() {
URL url = URL.valueOf("dubbo://10.10.10.10:2181")
.addParameter(Constants.ACCESS_KEY_ID_KEY, "ak")
.addParameter(CommonConstants.APPLICATION_KEY, "test")
.addParameter(Constants.SECRET_ACCESS_KEY_KEY, "sk");
Invocation invocation = new RpcInvocation();
AccessKeyAuthenticator helper = new AccessKeyAuthenticator();
assertThrows(RpcAuthenticationException.class, () -> helper.authenticate(invocation, url));
}

@Test
void testGetAccessKeyPairFailed() {
URL url = URL.valueOf("dubbo://10.10.10.10:2181")
.addParameter(Constants.ACCESS_KEY_ID_KEY, "ak");
AccessKeyAuthenticator helper = new AccessKeyAuthenticator();
Invocation invocation = mock(Invocation.class);
assertThrows(RuntimeException.class, () -> helper.getAccessKeyPair(invocation, url));
}

@Test
void testGetSignatureNoParameter() {
URL url = mock(URL.class);
Invocation invocation = mock(Invocation.class);
String secretKey = "123456";
AccessKeyAuthenticator helper = new AccessKeyAuthenticator();
String signature = helper.getSignature(url, invocation, secretKey, String.valueOf(System.currentTimeMillis()));
assertNotNull(signature);
}

@Test
void testGetSignatureWithParameter() {
URL url = mock(URL.class);
when(url.getParameter(Constants.PARAMTER_SIGNATURE_ENABLE_KEY, false)).thenReturn(true);
Invocation invocation = mock(Invocation.class);
String secretKey = "123456";
Object[] params = {"dubbo", new ArrayList()};
when(invocation.getArguments()).thenReturn(params);
AccessKeyAuthenticator helper = new AccessKeyAuthenticator();
String signature = helper.getSignature(url, invocation, secretKey, String.valueOf(System.currentTimeMillis()));
assertNotNull(signature);

Object[] fakeParams = {"dubbo1", new ArrayList<>()};
when(invocation.getArguments()).thenReturn(fakeParams);
String signature1 = helper.getSignature(url, invocation, secretKey, String.valueOf(System.currentTimeMillis()));
assertNotEquals(signature, signature1);

}
}
Loading