Probably client server encryption mismatch - encryption

The server encrypts a password using the following criteria:
AES.HashAlgorithm.MD5,
password = "dynamicweb",
salt="dwapac2015",
iteration=2,
Key size=AES.KeySize.Key192,
Initial Vector="dwdevelopmentsmm");
The server langauge is C#.
On the client side, the same encryption is done as follows:
public class Aes {
private static final String KEY_FACTORY_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String KEY_SPEC_ALGORITHM = "AES";
private static final int KEY_LENGTH = 192;
private static final int KEY_ITERATION_COUNT = 2;
public static String key = "dynamicweb";
public static String salt = "dwapac2015";
public static String cipherTransformation = "AES/CBC/PKCS5Padding";
public static String initializationVector = "dwdevelopmentsmm";
public static String encrypt(String payload) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
KeySpec spec = new PBEKeySpec(key.toCharArray(), salt.getBytes(), KEY_ITERATION_COUNT, KEY_LENGTH);
SecretKeySpec secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), KEY_SPEC_ALGORITHM);
Cipher cipher = Cipher.getInstance(cipherTransformation);
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(initializationVector.getBytes()));
byte[] encrypted = cipher.doFinal(payload.getBytes());
return new String(Base64.encodeBase64(encrypted));
}
}
The client language is Java.
The server returns the following error:
[Authenticate: 11/4/2015 6:42:09 AM]: [REQUEST: {UserName:BPlMi6RfvvWjntEW9Aw5Rw==,Password:BPlMi6RfvvWjntEW9Aw5Rw==}] System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed. at RestService.ServiceInterface.Helpers.DWCredentialsAuthProvider.CheckInDW(String userName, String password, Int32& currentUserID) at RestService.ServiceInterface.Helpers.DWCredentialsAuthProvider.TryAuthenticate(IServiceBase authService, String userName, String password) at ServiceStack.Auth.CredentialsAuthProvider.Authenticate(IServiceBase authService, IAuthSession session, String userName, String password, String referrerUrl) at ServiceStack.Auth.CredentialsAuthProvider.Authenticate(IServiceBase authService, IAuthSession session, Authenticate request) at ServiceStack.Auth.AuthenticateService.Authenticate(Authenticate request, String provider, IAuthSession session, IAuthProvider oAuthConfig) at ServiceStack.Auth.AuthenticateService.Post(Authenticate request) at lambda_method(Closure , Object , Object ) at ServiceStack.Host.ServiceRunner`1.Execute(IRequest request, Object instance, TRequest requestDto)"

Related

Spring security using LDAP and group membership

I am using spring security to verify if the user has passed in valid username and password.
I also want to validate if the user is a part of a particular group.
Though, the credentials verification is working, the group membership verification is not.
Do I need to configure ldapAuthoritiesPopulator?
Though, the credentials verification is working, the group membership verification is not.
I am assuming group membership is combination of ldap base and userDn.
Here is a code to help you.
public class LDAPDetail{
private String url; //your LDAP url
private Long timeout; // some timeout to connect LDAP
private String domain; // domain of user
private String userContainer; // typically value for OU=**,dc=**,dc=**
// You should be getting value for _domain_ and _userContainer_ from user's LDAP detail
}
public void validateUserDetails(){
LdapDetail ldapDetail = //gets user's value which you want to validate.
LdapTemplate ldapTemplate = build(ldapDetail, "username", "password");
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("cn", userName));
ldapTemplate.authenticate(LdapUtils.emptyLdapName(), filter.toString(), "password")
}
public static LdapTemplate build(LdapDetail ldapDetail, String userName, String password) {
LdapContextSource ldapContextSource = new LdapContextSource();
ldapContextSource.setBase(ldapDetail.getUserContainer());
ldapContextSource.setUrl(ldapDetail.getUrl());
ldapContextSource.setAnonymousReadOnly(true);
ldapContextSource.setCacheEnvironmentProperties(false);
ldapContextSource.setUserDn(ldapDetail.getDomain());
ldapContextSource.setBaseEnvironmentProperties(buildContextFor(ldapDetail, userName, password));
LdapTemplate ldapTemplate = new LdapTemplate(ldapContextSource);
ldapTemplate.setContextSource(ldapContextSource);
return ldapTemplate;
}
public static Map<String, Object> buildContextFor(LdapDetail ldapDetail, String userName, String password) {
Map<String, Object> env = new HashMap<>();
env.put(Context.REFERRAL, "throw");
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put("java.naming.factory.url.pkgs",
"org.jboss.naming:org.jnp.interfaces:org.jboss.naming:org.jnp.interfaces");
env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(ldapDetail.getTimeout()));
env.put(Context.PROVIDER_URL, ldapDetail.getUrl());
env.put("ldap.domain", ldapDetail.getDomain());
env.put(Context.SECURITY_PRINCIPAL, userName);
env.put(Context.SECURITY_CREDENTIALS, password);
return env;
}

How to read from encrypted CDC in Cassandra

We have implemented TDE for all our tables in Cassandra DSE. We generated a system key using AES/ECB/PKCS5Padding / 128 as cipher algorithm.
We have also enabled cdc for few tables that require cdc capture. Since TDE is enabled for the tables, cdc logs are also encrypted.
We need to push the cdc captures to kafka topics. We tried to decrypt the file using the system_key auto generated in the system_key file.
AES/ECB/PKCS5Padding:128:(key)
But we are getting java.security.InvalidKeyException: Illegal key size or default parameters
Can please advise if this is key can be used for decrypting the cdc logs or suggest any solution.
Below is the snippet we used for decrypting.
public class EncryptDecrypt {
public static String encrypt(String input, String key) {
byte[] crypted = null;
try {
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skey);
crypted = cipher.doFinal(input.getBytes());
} catch (Exception e) {
System.out.println(e.toString());
}
java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
return new String(encoder.encodeToString(crypted));
}
public static String decrypt(String input, String key) {
byte[] output = null;
try {
java.util.Base64.Decoder decoder = java.util.Base64.getDecoder();
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skey);
output = cipher.doFinal(decoder.decode(input));
} catch (Exception e) {
System.out.println(e.toString());
}
return new String(output);
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String key = "qhk9gDtvTUlLW9dnh/UMaw==";
String data = "ABC";
System.out.println(EncryptDecrypt.encrypt(data, key));
System.out.println(EncryptDecrypt.decrypt(EncryptDecrypt.encrypt(data, key), key));
}
}
The system_key file isn't used for direct encryption of the data, but for encryption of the actual encryption key that is stored in the dse_system.encrypted_keys. These keys are generated for every combination of algorithm/strength. See documentation for more details.

Basic Authentication with Retrofit

I am trying to build a client for a REST API using Retrofit. The API uses basic auth and I have been unable to authenticate using Retrofit.
I tested the API using the curl below and it works as expected
curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{some_json}' -u api_key: https://apitest.com/api/v1/customers
Below is the Retrofit client
public interface UserService {
String HOST = "https://apitest.com";
public static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
public static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(HOST)
.addConverterFactory(GsonConverterFactory.create());
/*
* CREATE/UPDATE User
*/
#POST("api/v1/customers")
Call<UserAPIResponse> userUpdate(#Body UserUpdateRequest userUpdateRequest);
static UserService newInstance(String userAPIKey) {
String credentials = userAPIKey + ":";
final String basic = "Basic "+ Base64.encodeBase64(credentials.getBytes());
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", basic);
requestBuilder.header("Accept", "application/json");
requestBuilder.method(original.method(),original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(BlueshiftUserService.class);
}
When I call updateUser on the UserService
Response<UserAPIResponse> response = UserService.userUpdate(userUpdateRequest).execute();
The response.code is 401 (unauthorized/authentication failed)
The curl command with -u and the same credentials works as expected.
The issue was with the credentials encoding. I wasnt sending it as string.
byte[] encodedAuth= Base64.encodeBase64(credentials.getBytes());
final String basic = "Basic " + new String(encodedAuth);
use these libraries in Gradle file
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.cookpad.android.rxt4a:rxt4a:0.9.0'
compile 'io.reactivex:rxjava:1.0.12'
and put this classes in your project
public class ServiceGenerator {
private static final String TAG = erviceGenerator.class.getSimpleName();
public static final int READ_TIMEOUT = 10000;
public static final int CONNECT_TIMEOUT = 100000;
// No need to instantiate this class.
private ServiceGenerator(){}
public static <S> S createService(Class<S> serviceClass, String
endpoint) {
// Call basic auth generator method without user and pass
return createService(serviceClass, endpoint, null, null); }
public static <S> S createService(Class<S> serviceClass, String
endpoint, String username, String password) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
// Set endpoint url and use OkHTTP as HTTP client
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(endpoint)
.setConverter(new GsonConverter(new Gson()))
.setClient(new OkClient(okHttpClient));
if (username != null && password != null) {
// Concatenate username and password with colon for authentication
final String credentials = username + ":" + password;
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
// Create Base64 encoded string
String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
request.addHeader("Authorization", string);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass); } }
and this interface
public class TodolyClient {
private static final String TAG = TodolyClient.class.getSimpleName();
public static final String ENDPOINT = "your base URL";
public interface TodolyService {
#GET("/wp-json/wc/v2/products")(your remaining url)
Observable<Object> isAuthenticated();
}
}
and call the below method in your main activity
private void createProject() {
final TodolyClient.TodolyService service =ServiceGenerator.createService(
TodolyClient.TodolyService.class, TodolyClient.ENDPOINT, "your user name",
"your password");
Observable<Object> observable = service.isAuthenticated();
AndroidCompositeSubscription compositeSubscription = new AndroidCompositeSubscription();
observable
.lift(new OperatorAddToCompositeSubscription<Object>(compositeSubscription))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override
public void onNext(Object project) {
android.util.Log.d(TAG, "onNext: "+project.toString());
}
#Override
public void onCompleted() {
android.util.Log.d(TAG, "onNext:commm " );
}
#Override
public void onError(Throwable e) {
android.util.Log.d(TAG, "onNext: eeeeeeeee"+e.getMessage());
}
});
}
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class), You can add any character set for encoding as the third parameter here.
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
Sorry, my code is in Kotlin, but can be easily translated to Java.
References: https://mobikul.com/basic-authentication-retrofit-android/

ASP.NET web handler run command as requesting user

From a web handler (xxx.ashx) I need to run a command as the same user using the web page and sending the request. I have IIS setup using impersonation, have code in my .ashx that shows it is impersonating the user, and then I use the C# Process.start() to run the command. (It's a .cmd file I am running)
The problem is that the .cmd file runs as the user assigned to the Application Pool and not the web user. I even tried this code:
WindowsImpersonationContext impersonationContext = ((WindowsIdentity)System.Security.Principal.WindowsIdentity.GetCurrent()).Impersonate();
Could this be an issue: I wrote the .ashx file and put just it under the IIS wwwroot/myapp folder and call it from a URL from a web browser. I have setup the Application Pool using the DefaultAppPool user and an OS user, but no difference.
I'm a novice with IIS & ASP too so this is like working in a black box.
We had to use the native windows method: CreateProcessAsUser(), and had to call DuplicateTokenEx() to duplicate the security token.
<%# WebHandler Language="C#" Class="batchRunSAS" %>
using System;
using System;
using System.IO;
using System.Web;
using System.Diagnostics;
using System.Security.Principal;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.ComponentModel;
public class batchRun : IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
//Call DuplicateTokenEx
//https://msdn.microsoft.com/en-us/library/ms682429(VS.85).aspx
//http://stackoverflow.com/questions/9095909/createprocessasuser-creating-window-in-active-session
Process process = null;
process = NativeMethods.CreateProcessAsUser("C:\\temp\\test.exe");
}
public bool IsReusable
{
get { return false; }
}
[SuppressUnmanagedCodeSecurity]
class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessID;
public Int32 dwThreadID;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
public const int GENERIC_ALL_ACCESS = 0x10000000;
public const int CREATE_NO_WINDOW = 0x08000000;
[
DllImport("kernel32.dll",
EntryPoint = "CloseHandle", SetLastError = true,
CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
]
public static extern bool CloseHandle(IntPtr handle);
[
DllImport("advapi32.dll",
EntryPoint = "CreateProcessAsUser", SetLastError = true,
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
]
public static extern bool
CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation);
[
DllImport("advapi32.dll",
EntryPoint = "DuplicateTokenEx")
]
public static extern bool
DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType,
ref IntPtr phNewToken);
public static Process CreateProcessAsUser(string filename, string args)
{
var hToken = WindowsIdentity.GetCurrent().Token;
var hDupedToken = IntPtr.Zero;
var pi = new PROCESS_INFORMATION();
var sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
try
{
if (!DuplicateTokenEx(
hToken,
GENERIC_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)TOKEN_TYPE.TokenPrimary,
ref hDupedToken
))
throw new Win32Exception(Marshal.GetLastWin32Error());
var si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "";
var path = Path.GetFullPath(filename);
var dir = Path.GetDirectoryName(path);
// Revert to self to create the entire process; not doing this might
// require that the currently impersonated user has "Replace a process
// level token" rights - we only want our service account to need
// that right.
using (var ctx = WindowsIdentity.Impersonate(IntPtr.Zero))
{
if (!CreateProcessAsUser(
hDupedToken,
path,
string.Format("\"{0}\" {1}", filename.Replace("\"", "\"\""), args),
ref sa, ref sa,
false, 0, IntPtr.Zero,
dir, ref si, ref pi
))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return Process.GetProcessById(pi.dwProcessID);
}
finally
{
if (pi.hProcess != IntPtr.Zero)
CloseHandle(pi.hProcess);
if (pi.hThread != IntPtr.Zero)
CloseHandle(pi.hThread);
if (hDupedToken != IntPtr.Zero)
CloseHandle(hDupedToken);
}
}
}
}

Request email from OAuthWebSecurity.RegisterMicrosoftClient

I am trying to integrate oauth authentication from an MVC 4 project to Microsoft (Live service). The followings lines in AuthConfig.cs have been uncommented:
OAuthWebSecurity.RegisterMicrosoftClient(
clientId: "XXX",
clientSecret: "XXX");
And, the app has been set up at https://manage.dev.live.com
Later, when OAuthWebSecurity.VerifyAuthentication is called, I get back the success status, but the email field is not in the returned data.
How can I request an email to be returned from VerifyAuthentication call issued again Microsoft account?
Thanks.
First, you should implement a 'MicrosoftScopedClient' class which implements 'IAuthenticationClient ' interface, and that should implement two methods of interface which is;
public class MicrosoftScopedClient : IAuthenticationClient
{
//Define following three keys in Web.Config file and use it in code, it will maintain code consistency.
private string clientId;
private string clientSecret;
private string scope;
private const string baseUrl = "https://login.live.com/oauth20_authorize.srf";
private const string tokenUrl = "https://login.live.com/oauth20_token.srf";
public void RequestAuthentication(HttpContextBase context, Uri returnUrl)
{
//Getting values of clientId, clientSecret and scope from Web.Config file
clientId=System.Configuration.ConfigurationManager.AppSettings["msClientId"].ToString();
clientSecret=System.Configuration.ConfigurationManager.AppSettings["msClientSecret"].ToString();
scope=System.Configuration.ConfigurationManager.AppSettings["msScope"].ToString();
string url = baseUrl + "?client_id=" + clientId + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString()) + "&scope=" + HttpUtility.UrlEncode(scope) + "&response_type=code";
//this will authenticate the user and register(only if user visited first time).
context.Response.Redirect(url);
}
public AuthenticationResult VerifyAuthentication(HttpContextBase context)
{
string code = context.Request.QueryString["code"];
string rawUrl = context.Request.Url.ToString();
//removing code portion
rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");
IDictionary<string, string> userData = GetUserData(code, rawUrl);
if (userData == null)
return new AuthenticationResult(false, ProviderName, null, null, null);
string id = userData["id"];
string username = userData["email"]; // here you'll get email id of user
userData.Remove("id");
userData.Remove("email");
AuthenticationResult result = new AuthenticationResult(true, ProviderName, id, username, userData);
return result;
}
}
////// Finally you need to register all stuffs in AuthConfig.cs and interact with Microsoft through our application.
OAuthWebSecurity.RegisterClient(new MicrosoftScopedClient(System.Configuration.ConfigurationManager.AppSettings["msClientId"].ToString(),
System.Configuration.ConfigurationManager.AppSettings["msClientSecret"].ToString(),
"wl.basic wl.emails"
)
, "Microsoft", null);

Resources