I am in the process of migrating users from an OAuth 2 system made with Symfony to Keycloak.
Create the users in Keycloak with the encrypted password is ok, but I can't find an algorithm equivalent to mine.
example of user creation:
Post
{
"firstName": "test_encryption",
"lastName":"test_encryption",
"email":"jeremy.rafflin.test#ageo.fr",
"credentials": [{
"type":"password",
"secretData":"{\"value\":\"zeR2Uapc+a/2qD5QR56gh3mVb+KOeZ2XU+rkWMK6B5A=\",\"salt\":\"OThjajM1WnVZWlI3UzZOLk12WjJsQS9VWWZXQXp0WGZGLm5tL2hGSVFzbw==\"}",
"credentialData": "{\"algorithm\":\"sha512\",\"hashIterations\":5000}"
}]
}
For the current encryption in PHP I am using https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Encoder/MessageDigestPasswordEncoder.php.
Which amounts to:
$password = 'toto';
$salt = '1234';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
for ($i=1; $i<5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encodedPassword = base64_encode($digest);
In the spring documentation, https://andifalk.github.io/reactive-spring-security-5-workshop/workshop-tutorial.html I see :
package org.springframework.security.crypto.factory;
public class PasswordEncoderFactories {
...
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new LdapShaPasswordEncoder());
encoders.put("MD4", new Md4PasswordEncoder());
encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new StandardPasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
...
}
So I thought my algorithm matched MessageDigestPasswordEncoder ("SHA-512") and tried to create a user, but it doesn't work:
"credentialData": "{"algorithm":"SHA-512","hashIterations":5000}"
Does my algorithm exist in keycloak or do I have to create a custom credential algorithm ?
Does my algorithm exist in keycloak or do I have to create a custom
credential algorithm ?
From the Keycloak Documentation:
Here’s an explanation of each policy type:
HashAlgorithm
Passwords are not stored as clear text. Instead they are
hashed using standard hashing algorithms before they are stored or
validated. The only built-in and default algorithm available is
PBKDF2.
Nevertheless, Keycloak allows you to customized and deploy your own algorithm by taking advantage of Service Provider Interfaces.
Related
I am trying to create an app in flutter and the sample code which I have is in java.
Here is the sample java code gist
https://gist.github.com/kapiljhajhria/72a22ff75e238878f539f7bb21026208
and here is my flutter code gist
https://gist.github.com/kapiljhajhria/795d1a7c7cf1c76ca8e327bf8b2f51de
Here is a brief summary of what I am doing
Generate a unique Session Key: AES Random Key 256
Encrypt JSON data using the Session Key from step 1
Generate SHA256 hash of JSON data
Encrypt generated hash from step 3, using session key from step 1.
Encrypt the session key using the public key. Public key provided as certificate.cer file. I copied the String value and added it to the class as a constant in order to make it easier to use. Not sure if this was the best approach.
Created a POST request with 3 Parameters. As shown in the java code. I think I am doing this part correctly.
The response which I will get will be encrypted using the session key from step 1. So i will have to decrypt that response data. Haven't reached this step yet.
I don't have access to the server where this request is being made.
Since the post request is being made using web view, I can't figure out a way to get proper error from my request. All I get is web page which says "Invalid Request"
So My first guess is that I am not using public key properly to encrypt my session key.
if that part is correct, then I am not encrypting the data properly or my encryption method doesn't match encryption methods used in java code the java code. Maybe the session key which I am generating is not correct.
Any help would be greatly appreciated. Thank you. If you need anything from me then please let me know.
I used this document as my reference: https://developers.emsigner.com/signer-gateway/api-reference/signing-documents.html
You need 2 packages: pointycastle and x509, and to import them as follows:
import 'package:pointycastle/export.dart';
import 'package:x509/x509.dart';
Then you need these helper functions:
Uint8List generateSessionKey() {
final r = Random();
return Uint8List.fromList(List<int>.generate(32, (_) => r.nextInt(256)));
}
RSAPublicKey parseCert(String pemData) {
final cert = parsePem(pemData).first as X509Certificate;
final pub = cert.publicKey as RsaPublicKey;
return RSAPublicKey(pub.modulus, pub.exponent);
}
Uint8List encryptUsingPublicKey(RSAPublicKey key, Uint8List data) {
final cipher = PKCS1Encoding(RSAEngine())
..init(true, PublicKeyParameter<RSAPublicKey>(key));
return cipher.process(data);
}
Uint8List encryptUsingSessionKey(Uint8List key, Uint8List data) {
final cipher = PaddedBlockCipher('AES/ECB/PKCS7')
..init(true, PaddedBlockCipherParameters(KeyParameter(key), null));
return cipher.process(data);
}
Uint8List sha256Digest(Uint8List data) {
return SHA256Digest().process(data);
}
And you'd build your 3 parameters like this:
final pem = File('cert2.pem').readAsStringSync();
final publicKey = parseCert(pem);
final sessionKey = generateSessionKey();
final encryptedSessionKey = encryptUsingPublicKey(publicKey, sessionKey);
final jsonString = json.encode(<String, dynamic>{
'FileType': 'PDF',
'SignaturePosition': 'Top-Left',
'AuthToken': 'some token',
'File': '',
'SUrl': 'http://localhost:3000/Success',
'FUrl': 'http://localhost:3000/Error',
'CUrl': 'http://localhost:3000/Cancel',
'ReferenceNumber': 'generate unique reference number',
});
final jsonBytes = utf8.encode(jsonString) as Uint8List;
final encryptedJson = encryptUsingSessionKey(sessionKey, jsonBytes);
final hash = sha256Digest(jsonBytes);
final encryptedHash = encryptUsingSessionKey(sessionKey, hash);
final p1 = base64.encode(encryptedSessionKey);
final p2 = base64.encode(encryptedJson);
final p3 = base64.encode(encryptedHash);
BUT, the big problem I see is how you then do the POST, because you want to be in a web page, right? And the normal flutter web view doesn't support an initial post. It does look like there's another package. Just search for flutter webview post.
By the way, if you don't want to use the pointycastle registry, you can rewrite encryptUsingSessionKey without as:
final cipher = PaddedBlockCipherImpl(
PKCS7Padding(),
ECBBlockCipher(AESEngine()),
)..init(true, PaddedBlockCipherParameters(KeyParameter(key), null));
return cipher.process(data);
Finally, at least until you get the web view issue understood, you can just use http to do the post. But, let it do the work of encoding the parameters and setting the content type, as follows:
final response = await http.post(
Uri.parse('https://somewhere/V3_0/Index'),
body: <String, String>{
'Parameter1': p1,
'Parameter2': p2,
'Parameter3': p3,
},
);
print(response.statusCode);
print(response.body);
Have a look at this project, It's an example for the Encryption by Flutter with a good documentation, have 3 types of encryptions:
AES encryptions
Fernet encryptions
Salsa20 encryptions
I'm using Web3j to interact with my deployed smart contract.
I've deployed my contract onto the testnet and can interact with it, however using the generated wrapper code, it requires my wallet.
Web3j web3 = Web3j.build(new HttpService("https://testnet-endpoint-rpc.com"));
Credentials credentials = WalletUtils.loadCredentials(
"coolpassword1", "src\\main\\resources\\path-to-key-store.keystore"
);
FastRawTransactionManager txMananger = new FastRawTransactionManager(web3, credentials, 365);
MySmartContract contract = MySmartContract.load(
"0x73292b80f99ffdc4e9a908865ce1d35fde7b736f", //Address for smartcontract
web3,
txMananger,
new DefaultGasProvider()
);
//Reading from the contract
String contractName = contract.contractName(BigInteger.valueOf(0)).send();
How can I read from the contract without credentials?
I believe you can use the encodedFunctions to read without credentials but for write, you need the credentials.
Ex: balances is one of the methods in the contract with a single input of an address
Function function =
new Function("balances",
Arrays.asList(new org.web3j.abi.datatypes.Address(walletAddress)),
new ArrayList());
String encodedFunction = FunctionEncoder.encode(function);
org.web3j.protocol.core.methods.response.EthCall response = this.web3.ethCall(
Transaction.createEthCallTransaction(walletAddress, ContractAddress, encodedFunction),
DefaultBlockParameterName.LATEST)
.sendAsync().get();
I am working to integrate my application with the Withings api with spring rest template.
But,while generating the Oauth signature I am getting the "Invalid signature". I am trying to devise a signature according to the API specification but I am not able to generate it successfully. I have mentioned the code that I used. Please, provide me some solutions.
private String generateSignature(String baseString, String secret) throws UnsupportedEncodingException {
String secretKey = consumerSecret + "&";
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), HMAC_SHA1SignatureMethod.SIGNATURE_NAME);
HMAC_SHA1SignatureMethod hmacsha = new HMAC_SHA1SignatureMethod(keySpec);
String signatureString = hmacsha.sign(baseString);
String base64Encode = new String((signatureString.getBytes()));
signature = URLEncoder.encode(base64Encode, "UTF-8");
For reference, http://oauth.withings.com/api
i faced the same issues before , it seems the signature need you params ( api params + oauth params ) to be ordered alphabetically .
You need also to give a correct secret word in making you signature based uri .
you can check if you want my php oauth lib ( more particulary in AbstractService.php ) for withing here
https://github.com/huitiemesens/PHPoAuthLib ( it s a fork of the original phpoauthlib with specific order for withings apis ... )
What is the difference between the following dynamo db query syntax:
We used to use
QueryRequest queryRequest = new QueryRequest().withTableName(TABLE).withKeyConditions(keyConditions)....;
and in the latest documentation i see:
table.query("Id", replyId,
null, ///RangeKeyCondition - not used in this example
"PostedBy = :val", //FilterExpression
which one should we use?
is it a new syntax? differences?
Thanks
Different flavor, same DynamoDB API. The new Document API was introduced in Oct 2014
.. the new Document API allows the direct use of plain old Java data
types and has less boilerplate. In fact, the Dynamo Document API can
be used to entirely subsume what you can do with the low level client
(i.e. AmazonDynamoDBClient) but with a much cleaner programming model
and less code.
I personally still use AmazonDynamoDBClient (your first code sample)
#Bean
public AmazonDynamoDB amazonDynamoDB() {
String accesskey = "";
String secretkey = "";
//
// creating dynamo client
BasicAWSCredentials credentials = new BasicAWSCredentials(accesskey, secretkey);
AmazonDynamoDB dynamo = new AmazonDynamoDBClient(credentials);
dynamo.setRegion(Region.getRegion(Regions.US_WEST_2));
return dynamo;
}
#Bean
public DynamoDBMapper dynamoDBMapper() {
return new DynamoDBMapper(amazonDynamoDB());
}
#Bean
public DynamoDBTemplate dynamoDBTemplate() {
return new DynamoDBTemplate(amazonDynamoDB());
}
Use DynamoDbMapper for scanning the data :
DynamoDBQueryExpression<T> query = new DynamoDBQueryExpression<>();
query.addExpressionAttributeNamesEntry("xyz", "abc");
List<T> results = dynamoDBMapper.query(T.class, query);
modify your query and will be able to search data.
I am trying to get amazon cognito to work. If I run the code to generate a login token from a standalone java program it works.
public class cognito extends HttpServlet
{
public static void main(String[] args) throws Exception {
AWSCredentials credentials = new BasicAWSCredentials("*******", "********");
AmazonCognitoIdentityClient client =
new AmazonCognitoIdentityClient(credentials);
client.setRegion(Region.getRegion(Regions.EU_WEST_1));
GetOpenIdTokenForDeveloperIdentityRequest tokenRequest =
new GetOpenIdTokenForDeveloperIdentityRequest();
tokenRequest.setIdentityPoolId("*************");
HashMap<String, String> map = new HashMap<String, String>();
//Key -> Developer Provider Name used when creating the identity pool
//Value -> Unique identifier of the user in your <u>backend</u>
map.put("test", "AmazonCognitoIdentity");
//Duration of the generated OpenID Connect Token
tokenRequest.setLogins(map);
tokenRequest.setTokenDuration(1000l);
GetOpenIdTokenForDeveloperIdentityResult result = client
.getOpenIdTokenForDeveloperIdentity(tokenRequest);
String identityId = result.getIdentityId();
String token = result.getToken();
System.out.println("id = " + identityId + " token = " + token);
}
}
However when I run this code from a servlet on a redhat linux server, it always times out.
Any suggestion would be helpful
map.put("test", "AmazonCognitoIdentity");
are you sure your developer provider name is "test"?
you can see it in your cognito identity pool edit page.
And "AmazonCognitoIdentity" should be your own unique user-id.
Without the actual exception, it is hard to tell what is the exact issue. It could be that something else running in your servlet engine is setting a much more aggressive socket timeout than the default when it runs from the command line. You might want to explicitly set the connection and socket timeouts using methods using this class http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html and pass it in to the identity client constructor.