Keycloak - Retrieve RSA public key - oauth-2.0

I have an app deployed with docker, one of the microservices is a jboss/keycloak server. Everything works fine, but keycloak RSA public key need to be retrieved manually. Is it possible to retrieve RSA public key through REST API?

The url https://<keycloak-server>/auth/realms/<realm> contains a json response with the public key. This isn't advertised so it may change or go away. Using https://<keycloak-server>/auth/realms/<realm>/protocol/openid-connect/certs and setting up something to monitor the jwks response would be a much more maintainable way of handling it.

Since version 14 or so, this is now https://<keycloak-server>/realms/<realm>, i.e., no /auth in the path anymore.

Just for lazy people, as mentioned by #davidav.
It means you get the regular openid-connect keys via
https://<keycloakserver>/realms/<realm>/protocol/openid-connect/certs

Related

Encryption with Azure Key Vault CryptographyClient - where is encrypt/decrypt happenning? my backend or Azure server side

I'm currently using Azure Key vault .net SDK to encrypt/decrypt some data. Azure SDK for .net has a build-in Class called "CryptographyClient" and it has built-in method for doing that:
CryptographyClient.decrypt and CryptographyClient.encrypt
The key I'm using is a RSA key and algorithm I use is RsaOaep, so I assume it is asymmetric encryption. I followed this article to write my c# code. Basically, I get the public part of the asymmetric key from the key vault first, then use it to create a CryptographyClient.
Usually, for asymmetric encryption, we gonna use the public key to encrypt while the private key is for decryption only. So basically, the private key will never leave the Azure Key Vault (always at the Azure server, is it true?).
Now my question is:
when I call CryptographyClient.encrypt, is it only running on the client-side (my local server)? or will it send my plaintext to Azure server and send back the encrypted text?
when I call CryptographyClient.decrypt, since the private key should never leave Azure and you can only decrypt with private key, is it only running on the Azure server-side? Mean that my local server will need to send the encrypted text to Azure and wait for decryption?
I got a feeling that both of those methods are only happening on the client-side and this is what I want. But then it doesn't make sense for decryption.
Thanks for the clarification as I can't find any MS documentation for this.
Operations that use the public key - if they can download the public get i.e., caller has the "get" permission - will happen on the client. They public key is download and operation performed. If the caller doesn't have the "get" permission on that key, the operation will be performed on the service.
These operations include:
encrypt
verify
wrap
Operations that require the private key will always be performed on the service, unless you created a CryptographyClient from your own JSON web key (JWK) that has both the public and private keys.
These operations include:
*decrypt
*sign
*unwrap
All of the encryption/decryption occurs on the server side since that’s where the private key lives.
The CryptographyClient API is based on REST :
https://learn.microsoft.com/en-us/rest/api/keyvault/keys/encrypt
https://learn.microsoft.com/en-us/rest/api/keyvault/keys/decrypt/decrypt
You can run a Fiddler trace while executing your code to see the server communication.

Correct way of storing API Keys in flutter following best practises

Which is the correct way(best practice) of adding secret API keys in flutter in case I want to push the code on github. I've made a simple app that consumes an API but I used the key in a crud way just to test whether the app is working. Usually from my experience developing applications in the back-end, Keys are stored somewhere and in different file then one would simply import it to the required file that needs the API_KEY and exclude the file in .gitignore file.
So far I have also implemented this approach:
Folder tree
-lib
-auth
-keys.dart
-secrets.json
secrets.json
This is where I will add the KEY and specify this file in .gitignore to be excluded from being added in github when I push my code.
//Add API KEY HERE
{
"api_key": "ee4444444a095fc613c5189b2"
}
keys.dart
import 'dart:async' show Future;
import 'dart:convert' show json;
import 'package:flutter/services.dart' show rootBundle;
class Secret {
final String apikey;
Secret({this.apikey=""});
factory Secret.fromJson(Map<String, dynamic>jsonMap){
return new Secret(apikey:jsonMap["api_key"]);
}
}
class SecretLoader {
final String secretPath;
SecretLoader({this.secretPath});
Future<Secret> load() {
return rootBundle.loadStructuredData<Secret>(this.secretPath,
(jsonStr) async {
final secret = Secret.fromJson(json.decode(jsonStr));
return secret;
});
}
}
I feel like this approach is too much. I would like to get suggestions of a better approach.
EDIT: Look at J. Saw's comment below.
EDIT 2: The issue in described at the bottom has been fixed in firebase-config 19.0.2.
Use Firebase Remote Config. Inside the Firebase console, inside the menu, scroll down to Grow and then Remote Config. Here you can add a parameter with a value. When you're done don't forget to publish the changes. It's kind of subtle.
Now install firebase_remote_config for Flutter.
After importing everything, you can retrieve your value using this code:
RemoteConfig remoteConfig = await RemoteConfig.instance;
await remoteConfig.fetch(expiration: Duration(hours: 1));
await remoteConfig.activateFetched();
remoteConfig.getValue('key').asString();
This way, the API key or token is never part of your application.
Note: there is currently an issue where you get a warning stating the application's name is not set, but this won't affect functionality.
For secure storage you have to rely on the corresponding native platforms, both iOs and Android provide a mechanism to securely store keys. You can implement it by yourself and use the flutter channels to obtain and store the keys. Information about this mechanism can be read here:
Android Keystore
iOs KeyChain
Also, you can use this flutter plugin, which uses the services mentioned above and provides a dart object to access the secure storage.
API Keys must be hard coded.
Why?
Because it's impossible to retrieve the key from an external source without having a key to that source, and you can't store it securely at the OS level without having the key within the app.
Example
When you connect your app to a Firebase project or Google Cloud servers, you basically authenticate using a hard-coded API key, that you have downloaded into your app when initiating your cloud project (read more).
Security
There are two essential steps to secure your critical assets:
Keep your secret keys out of version control.
Use obfuscation to make it difficult for attackers to reverse engineer your application, and reveal your API Key.
IMO, those are the only steps you can take to secure your app API Key.
As mentioned, if the key is a secrete and you would like to protect it then simply do not put it in the client app. The app can be de-compiled and the key can be extracted for person willing to target your client.
I would delegate the task of communicating with this API to your Application Server. You can put the key in your server and have your server communicate with this external API and relay the response to the client.
Edit: Another approach, which is less secure but more convenient is to obfuscate your code using something like proguard. See this page for flutter instruction on android app: https://flutter.io/android-release/
The best practice should be to create a Firebase function, and then have that function use the secrets storage. This approach keeps the secrets out of your source code so there are no issues with sharing the code, and stores them securely. Firebase authenticates your app (and users if you use the login feature).
Secret Parameters
Call functions from your app
You can use flutter_secure_storage from the oficial Flutter Packages

Heroku - Keep Keys Hidden Upon Inpect Element

I have deployed an application to Heroku and have used the heroku config:set command to set environmental variables such as keys for certain things (Google Maps API, for example). When I view the page and inspect element, the key shows up in the url in the console. Should this be the case? I was under the impression that keys should be kept hidden to keep others from knowing what they are for security reasons. Please advise. Thank you.
You can't. Anything which is sent to the client is not secret. That includes any values used in javascript.
But don't worry - most API's like Google Maps use a public key. And applications where you use Oauth only allow a whitelist of callback domains.
In fact in the Google Maps Javascript API your API key is used in constructing the URLs used to request resources so attempting to hide it would be a true fools errand.
Some API's do however provide client secrets for calling the API from the server side. These should be kept secret and placed in an ENV var on the server.

rack-saml Assertion Consumer Service binding

I am using rack-saml as middleware with omniauth-shibboleth to allow my app to work as a Service Provider.
I would like to know how to set the binding for an Assertion Consumer Service (ACS) url?
Presently my ACS url binding is 'any'. However, I have searched in rack-saml and omniauth-shibboleth to find where this is being set, and have not been able to find it.
I am trying to get my app working with testshib.org in hopes of using the app with a similarly configured Identity Provider (IdP).
I have uploaded my metadata to testshib.org. I am not sure how to implement their custom shibboleth.xml file; however my app is able to redirect to their IdP login page and cookies are set by their IdP.
Hear are some errors from the testhib.org logs.
20:14:15.864 - WARN [org.opensaml.saml2.binding.AuthnResponseEndpointSelector:206] - Relying party 'https://test_shib.com' requested the response to be returned to endpoint with ACS URL 'https://test_shib.com:443/auth/shibboleth/callback' and binding 'any' however no endpoint, with that URL and using a supported binding, can be found in the relying party's metadata
20:14:15.864 - ERROR [edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler:447] - No return endpoint available for relying party https://test_shib.com
Any help would be greatly appreciated.
There may be a better way to do this; but I got things working by overriding Onelogin::Saml::Authrequest (and the other classes that called Onelogin::Saml::Authrequest) and then changing AssertionConsumerServiceURL to AssertionConsumerService in the create method.
in lib/rack/saml.rb you will find:
#config['assertion_consumer_service_uri'] ||= "#{saml_sp_prefix}#{#config['protected_path']}"
So, in your config/rack-saml.yml you can configure it like this (and you may need to if having the port number in the uri causes problems):
assertion_consumer_service_uri: https://www.abc.edu/users/auth/shibboleth/callback
Also, you shouldn't need anything from their shibboleth2.xml file, Just put the certificate from their provider's xml in your metadata.yml config file:
---
idp_lists:
https://idp.testshib.org/idp/shibboleth:
certificate: |-
-----BEGIN CERTIFICATE-----
MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEV
...
8K/qhmFT2nIQi538n6rVYLeWj8Bbnl+ev0peYzxFyF5sQA==
-----END CERTIFICATE-----
saml2_http_redirect: https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO

Amazon S3 : access without Secret Key

I am developing an iOS app which saves picture in an Amazon S3 server. Unfortunately, the owner of the server prefers not to give me his secret key. Instead, he generates and provides me with a signature he says I can use to upload a file.
The problem is that I cannot find a way to perform that. Especially with the Amazon S3 sample "S3Uploader".
Do you have any idea about that ?
Thanks in advance
The secret key is only needed to calculate the signature, so if you already have a signature you don't need it. You do however need the access key id (so that amazon knows which secret key to use to validate the signature).
I had a quick look at the iOS sdk docs and it doesn't look like they provide a way to short-circuit the signature calculation process. Uploading a file is easy though, you just make a PUT request:
PUT /ObjectName HTTP/1.1
Host: BucketName.s3.amazonaws.com
Date: date
Authorization: signatureValue
Content-Length: 1234
There are details of extra headers you can use in the documentation.
Another workflow is that instead of providing you with signature values, the remote service could use the amazon STS api to return temporary credentials authorised only to upload files to the specified bucket. If you go this route then you would be able to just use the SDK provided by amazon.

Resources