diff --git a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g index f91e6ab281..884137513b 100644 --- a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g +++ b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g @@ -127,6 +127,8 @@ UNESCAPE_XML : 'unescapeXml'; UNESCAPE_CSV : 'unescapeCsv'; UNESCAPE_HTML3 : 'unescapeHtml3'; UNESCAPE_HTML4 : 'unescapeHtml4'; +BASE64_ENCODE : 'base64Encode'; +BASE64_DECODE : 'base64Decode'; // 1 arg functions SUBSTRING_AFTER : 'substringAfter'; @@ -226,4 +228,4 @@ ESC ATTRIBUTE_NAME : ( ~('$' | '{' | '}' | '(' | ')' | '[' | ']' | ',' | ':' | ';' | '/' | '*' | '\'' | ' ' | '\t' | '\r' | '\n' | '0'..'9') ~('$' | '{' | '}' | '(' | ')' | '[' | ']' | ',' | ':' | ';' | '/' | '*' | '\'' | ' ' | '\t' | '\r' | '\n')* - ); + ); \ No newline at end of file diff --git a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g index 3f77190c8a..01a0495490 100644 --- a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g +++ b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g @@ -73,7 +73,7 @@ tokens { } // functions that return Strings -zeroArgString : (TO_UPPER | TO_LOWER | TRIM | TO_STRING | URL_ENCODE | URL_DECODE | ESCAPE_JSON | ESCAPE_XML | ESCAPE_CSV | ESCAPE_HTML3 | ESCAPE_HTML4 | UNESCAPE_JSON | UNESCAPE_XML | UNESCAPE_CSV | UNESCAPE_HTML3 | UNESCAPE_HTML4 ) LPAREN! RPAREN!; +zeroArgString : (TO_UPPER | TO_LOWER | TRIM | TO_STRING | URL_ENCODE | URL_DECODE | BASE64_ENCODE | BASE64_DECODE | ESCAPE_JSON | ESCAPE_XML | ESCAPE_CSV | ESCAPE_HTML3 | ESCAPE_HTML4 | UNESCAPE_JSON | UNESCAPE_XML | UNESCAPE_CSV | UNESCAPE_HTML3 | UNESCAPE_HTML4 ) LPAREN! RPAREN!; oneArgString : ((SUBSTRING_BEFORE | SUBSTRING_BEFORE_LAST | SUBSTRING_AFTER | SUBSTRING_AFTER_LAST | REPLACE_NULL | REPLACE_EMPTY | PREPEND | APPEND | FORMAT | STARTS_WITH | ENDS_WITH | CONTAINS | JOIN | JSON_PATH) LPAREN! anyArg RPAREN!) | (TO_RADIX LPAREN! anyArg (COMMA! anyArg)? RPAREN!); @@ -138,4 +138,4 @@ expression : DOLLAR LBRACE attributeRefOrFunctionCall (COLON functionCall)* RBRA ^(EXPRESSION attributeRefOrFunctionCall functionCall*); query : expression EOF -> - ^(QUERY expression); + ^(QUERY expression); \ No newline at end of file diff --git a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/output/AttributeExpressionLexer.tokens b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/output/AttributeExpressionLexer.tokens index 0265bfb982..e370eb6593 100755 --- a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/output/AttributeExpressionLexer.tokens +++ b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/output/AttributeExpressionLexer.tokens @@ -86,3 +86,5 @@ URL_DECODE=72 URL_ENCODE=73 UUID=74 WHITESPACE=75 +BASE64_ENCODE=76 +BASE64_DECODE=77 diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java index 7d04f6e5ce..49c2a057d9 100644 --- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java +++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java @@ -94,6 +94,8 @@ import org.apache.nifi.attribute.expression.language.evaluation.functions.ToUppe import org.apache.nifi.attribute.expression.language.evaluation.functions.TrimEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.functions.UrlDecodeEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.functions.UrlEncodeEvaluator; +import org.apache.nifi.attribute.expression.language.evaluation.functions.Base64DecodeEvaluator; +import org.apache.nifi.attribute.expression.language.evaluation.functions.Base64EncodeEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.functions.UuidEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.literals.BooleanLiteralEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.literals.NumberLiteralEvaluator; @@ -192,6 +194,8 @@ import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpre import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TRUE; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.URL_DECODE; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.URL_ENCODE; +import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.BASE64_DECODE; +import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.BASE64_ENCODE; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ESCAPE_JSON; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ESCAPE_CSV; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ESCAPE_HTML3; @@ -933,6 +937,14 @@ public class Query { verifyArgCount(argEvaluators, 0, "urlDecode"); return addToken(new UrlDecodeEvaluator(toStringEvaluator(subjectEvaluator)), "urlDecode"); } + case BASE64_ENCODE: { + verifyArgCount(argEvaluators, 0, "base64Encode"); + return addToken(new Base64EncodeEvaluator(toStringEvaluator(subjectEvaluator)), "base64Encode"); + } + case BASE64_DECODE: { + verifyArgCount(argEvaluators, 0, "base64Decode"); + return addToken(new Base64DecodeEvaluator(toStringEvaluator(subjectEvaluator)), "base64Decode"); + } case ESCAPE_CSV: { verifyArgCount(argEvaluators, 0, "escapeCsv"); return addToken(CharSequenceTranslatorEvaluator.csvEscapeEvaluator(toStringEvaluator(subjectEvaluator)), "escapeJson"); diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/Base64DecodeEvaluator.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/Base64DecodeEvaluator.java new file mode 100644 index 0000000000..8224f16f69 --- /dev/null +++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/Base64DecodeEvaluator.java @@ -0,0 +1,55 @@ +/* + * 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.nifi.attribute.expression.language.evaluation.functions; + +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.Map; + +import org.apache.nifi.attribute.expression.language.evaluation.Evaluator; +import org.apache.nifi.attribute.expression.language.evaluation.QueryResult; +import org.apache.nifi.attribute.expression.language.evaluation.StringEvaluator; +import org.apache.nifi.attribute.expression.language.evaluation.StringQueryResult; + +public class Base64DecodeEvaluator extends StringEvaluator { + + private final Evaluator subject; + + public Base64DecodeEvaluator(final Evaluator subject) { + this.subject = subject; + } + + @Override + public QueryResult evaluate(final Map attributes) { + final String subjectValue = subject.evaluate(attributes).getValue(); + if (subjectValue == null) { + return new StringQueryResult(null); + } + + try { + return new StringQueryResult(new String(Base64.getDecoder().decode(subjectValue), "UTF-8")); + } catch (final UnsupportedEncodingException e) { + return null; // won't happen. It's UTF-8 + } + } + + @Override + public Evaluator getSubjectEvaluator() { + return subject; + } + +} diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/Base64EncodeEvaluator.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/Base64EncodeEvaluator.java new file mode 100644 index 0000000000..296f686851 --- /dev/null +++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/Base64EncodeEvaluator.java @@ -0,0 +1,55 @@ +/* + * 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.nifi.attribute.expression.language.evaluation.functions; + +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.Map; + +import org.apache.nifi.attribute.expression.language.evaluation.Evaluator; +import org.apache.nifi.attribute.expression.language.evaluation.QueryResult; +import org.apache.nifi.attribute.expression.language.evaluation.StringEvaluator; +import org.apache.nifi.attribute.expression.language.evaluation.StringQueryResult; + +public class Base64EncodeEvaluator extends StringEvaluator { + + private final Evaluator subject; + + public Base64EncodeEvaluator(final Evaluator subject) { + this.subject = subject; + } + + @Override + public QueryResult evaluate(final Map attributes) { + final String subjectValue = subject.evaluate(attributes).getValue(); + if (subjectValue == null) { + return new StringQueryResult(null); + } + + try { + return new StringQueryResult(Base64.getEncoder().encodeToString(subjectValue.getBytes("UTF-8"))); + } catch (final UnsupportedEncodingException e) { + return null; // won't happen. + } + } + + @Override + public Evaluator getSubjectEvaluator() { + return subject; + } + +} diff --git a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java index 29dbcc0177..3b22e134ec 100644 --- a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java +++ b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java @@ -1020,6 +1020,22 @@ public class TestQuery { verifyEquals("${filename:substringAfter('-'):toNumber():toRadix(36, 3):toUpper()}", attributes, "073"); } + @Test + public void testBase64Encode(){ + final Map attributes = new HashMap<>(); + attributes.put("userpass", "admin:admin"); + verifyEquals("${userpass:base64Encode()}", attributes, "YWRtaW46YWRtaW4="); + + } + + @Test + public void testBase64Decode(){ + final Map attributes = new HashMap<>(); + attributes.put("userpassbase64", "YWRtaW46YWRtaW4="); + verifyEquals("${userpassbase64:base64Decode()}", attributes, "admin:admin"); + + } + @Test public void testDateFormatConversion() { final Map attributes = new HashMap<>(); diff --git a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc index 5e721662e9..98778e4e40 100644 --- a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc +++ b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc @@ -1179,6 +1179,42 @@ Each of the following functions will encode a string according the rules of the + +[.function] +=== base64Encode + +*Description*: [.description]#Returns a Base64 encoded string. This is useful for being able to transfer binary data as ascii.# + +*Subject Type*: [.subject]#String# + +*Arguments*: No arguments + +*Return Type*: [.returnType]#String# + +*Examples*: We can Base64-Encoded an attribute named "payload" by using the Expression + `${payload:base64Encode()}` If the attribute payload had a value of "admin:admin" + then the Expression `${payload:base64Encode()}` will return "YWRtaW46YWRtaW4=". + + + + +[.function] +=== base64Decode + +*Description*: [.description]#Reverses the Base64 encoding on given string.# + +*Subject Type*: [.subject]#String# + +*Arguments*: No arguments + +*Return Type*: [.returnType]#String# + +*Examples*: If we have a Base64-Encoded attribute named "payload" with the value + "YWRtaW46YWRtaW4=", then the Expression + `${payload:base64Decode()}` will return "admin:admin". + + + [[searching]] == Searching