I recently had a request from a client who wanted to use a third party service that didn’t provide an authentication key. Instead I need to use a simple username and password combo that the client didn’t want exposed in our code repository where we generally keep our configuration values.
Having heard about encrypted configuration values, I set out to learn how to use them. I found a variety of resources out there, but none of them really walked me through from Point A to Point B. I had to kind of make some logical leaps to figure out what to do. It turns out that this is really straightforward once you know what to do.
First things first, take the value you want to encrypt and open up your system console to the Crypto Support tab (/system/console/crypto). It should look like this:
Just put the value you want to keep safe in the “Plain Text” field and click the Protect button. You’ll get back a value that looks something like this {89cb4befeb375b865332fed9bbde85b8842a2318be4901851c3b5a0495c49f13dad8b4cfd38a6fa26f07ea361ea4994e}
There is one “gotcha” to be aware of. When you encrypt the password using the Crypto Support tool, the encryption is specific to the instance you are running. If you want to re-use that same encrypted value, you will need to copy the crypto keys as helpfully outlined here by Nate Yolles: http://www.nateyolles.com/blog/2017/05/sharing-crypto-keys-in-aem-63
You’ll want to copy that encrypted value and place it in your configuration file. It might look something like this:
Next you’ll want a service that pulls these configuration values in and makes them available for interaction with your third party application. Nate Yolles wrote an excellent and very helpful blog on how to use OSGi annotations to do this (http://www.nateyolles.com/blog/2017/05/osgi-declarative-services-annotations-in-aem) so for our purposes, we’ll just note that your service will look something like this:
package com.example.servlets;import com.adobe.granite.crypto.CryptoException;import com.adobe.granite.crypto.CryptoSupport;@Component(immediate=true,
service=Servlet.class,
property={
Constants.SERVICE_DESCRIPTION+"=Example Servlet","sling.servlet.methods="+ HttpConstants.METHOD_POST})@Designate(ocd=ExampleServlet.Configuration.class)publicclassExampleServletextends SlingAllMethodsServlet {private String apiPassword;private String apiUsername;protected CryptoSupport cryptoSupport;@ReferencepublicvoidbindCryptoSupport(CryptoSupport cryptoSupport){this.cryptoSupport= cryptoSupport;}publicvoidunbindCryptoSupport(CryptoSupport cryptoSupport){this.cryptoSupport= cryptoSupport;}@OverrideprotectedvoiddoPost(final SlingHttpServletRequest req,final SlingHttpServletResponse resp)throws ServletException, IOException {// some code here
String username = apiUsername;
String password = getPassword();
someAPIFunction(username, password);// more code here
}private String getPassword(){
String passwd ="";try{if(this.cryptoSupport.isProtected(apiPassword)){
passwd =this.cryptoSupport.unprotect(apiPassword);}elseif(apiPassword.length()> 0){
passwd = apiPassword;}}catch(CryptoException ex){
logger.error("A helpful log message");}catch(NullPointerException ex){
logger.error("A helpful null pointer exception message");}return passwd;}@Activate@ModifiedprotectedvoidActivate(Configuration config){
apiPassword = config.encryptedpassword();
apiUsername = config.username();}@ObjectClassDefinition(name ="Example Servlet - OSGi")public@interface Configuration {@AttributeDefinition(
name ="API Password",
description ="Pull the API password from the configuration settings",
type = AttributeType.STRING)
String encryptedpassword()default"";@AttributeDefinition(
name ="API Username",
description ="Pull the API username from the configuration settings",
type = AttributeType.STRING)
String username()default"";}
Note that although I’m checking in the getPassword() function to make sure I’m decrypting properly, in my experience, this just works. My service doesn’t actually require me to make the “unprotect” call, but I left it here just in case it is helpful to anyone else.
It really is simple once you know what you’re doing and in retrospect, I was surprised that it took me as long as it did to figure out.
Author Bio
Curtis Mortensen is a Senior AEM Architect at Hoodoo Digital. He has been working in the web application space for over fifteen years. He’s earned a Bachelors in Computer Engineering from the University of Utah and has worked at a variety of software development positions from startups to huge global agencies. He started working with AEM over six years ago and has enjoyed building implementations for a diverse set of clients. Along the way, Curtis earned the AEM Developer and AEM Architect certifications from Adobe.
He and his wife have adopted four kids, three dogs and a changing number of rabbits. When that doesn’t keep him busy, he enjoys reading (mostly fantasy novels) and playing video games.
Hoodoo Digital brings simplicity to the complexity of AEM implementations. Using an optimized implementation process and a suite of software tools, Hoodoo delivers solutions that use the latest features of AEM and provide a highly effective way for marketing teams to accomplish their daily goals. To learn more, visit https://hoodoo.digital or follow us on Twitter: @HoodooDigital.