From b5ca4adc2d3f26df46a7a15dca312c01f3143496 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 14 Nov 2016 22:40:24 +0100 Subject: [PATCH] logstash 5.0 fix --- .travis.yml | 4 +- CHANGELOG.md | 2 + lib/logstash/codecs/leef.rb | 88 +++++++++++++++---------- logstash-codec-leef-3.0.1-java.gem.old | Bin 0 -> 13312 bytes logstash-codec-leef.gemspec | 5 +- spec/codecs/leef_spec.rb | 76 ++++++++++----------- 6 files changed, 100 insertions(+), 75 deletions(-) create mode 100644 logstash-codec-leef-3.0.1-java.gem.old diff --git a/.travis.yml b/.travis.yml index 350c4eb..97a2f46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ sudo: false language: ruby cache: bundler +jdk: + - oraclejdk8 rvm: - - jruby-1.7.23 + - jruby-1.7.25 script: - bundle exec rspec spec diff --git a/CHANGELOG.md b/CHANGELOG.md index 484935b..6d94238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +# 3.0.1 + - Breaking: Updated plugin to use new Java Event APIs for Elastic Stack/Logstash 5.x # 1.0.0 (fork from CEF 2.1.3) - Slightly changed the format that the codec is available for the IBM Qradar Log Event Extended Format (LEEF) # 2.1.3 diff --git a/lib/logstash/codecs/leef.rb b/lib/logstash/codecs/leef.rb index c297c16..af57ea5 100644 --- a/lib/logstash/codecs/leef.rb +++ b/lib/logstash/codecs/leef.rb @@ -10,9 +10,13 @@ class LogStash::Codecs::LEEF < LogStash::Codecs::Base config_name "leef" + + # Field is to disable the leef header, which can be helpful for generating WCollect messages over syslog + config :leefheader, :validate => boolean, :default => true # Field to enable the default syslog header, which uses the default `%{host}` field for hostname and the timestamp is generated by the codec parsing time. If no value is set the hostname is set to the `hostname` value where logstash is running. config :syslogheader, :validate => :boolean, :default => true + config :sysloghost, :validate => :string, :default => "logstash" # Device vendor field in LEEF header. The new value can include `%{foo}` strings # to help you build a new value from other parts of the event. @@ -24,7 +28,7 @@ class LogStash::Codecs::LEEF < LogStash::Codecs::Base # Device version field in LEEF header. The new value can include `%{foo}` strings # to help you build a new value from other parts of the event. - config :version, :validate => :string, :default => "2.3.3" + config :version, :validate => :string, :default => "5.0.0" # EventID field in LEEF header. The new value can include `%{foo}` strings # to help you build a new value from other parts of the event. @@ -55,11 +59,19 @@ class LogStash::Codecs::LEEF < LogStash::Codecs::Base # Fields to be included in LEEF extension part as key/value pairs config :fields, :validate => :array, :default => [] +HEADER_FIELDS = ['leef_version', 'leef_vendor', 'leef_product', 'leef_device_version', 'leef_eventid'] + public def initialize(params={}) super(params) end +private +def store_header_field(event,field_name,field_data) + #Unescape pipes and backslash in header fields + event.set(field_name,field_data.gsub(/\\\|/, '|').gsub(/\\\\/, '\\')) unless field_data.nil? +end + public def decode(data) # Strip any quotations at the start and end, flex connectors seem to send this @@ -73,25 +85,24 @@ def decode(data) # gives an "SyntaxError: (RegexpError) invalid pattern in look-behind" for the variable length look behind. # Therefore one edge case is not handled properly: \\| (this should split, but it does not, because the escaped \ is not recognized) # TODO: To solve all unescaping cases, regex is not suitable. A little parse should be written. - event['leef_version'], event['leef_vendor'], event['leef_product'], event['leef_device_version'], event['leef_eventid'], *message = data.split /(?<=[^\\]\\\\)[\|]|(?" + syslogtime + sysloghost = sanitize_header_field(event.sprintf(@sysloghost)) if sysloghost == "" - sysloghost = Socket.gethostname - end - end + sysloghost = Socket.gethostname + end + end + vendor = sanitize_header_field(event.sprintf(@vendor)) vendor = self.class.get_config["vendor"][:default] if vendor == "" @@ -153,19 +166,26 @@ def encode(event) # Should also probably set the fields sent - if @syslogheader == true - sheader = [syslogtime, sysloghost].join(" ") - header = ["LEEF:1.0", vendor, product, version, eventid].join("|") - values = @fields.map {|fieldname| get_value(fieldname, event)}.compact.join(" ") - - @on_event.call(event, "#{sheader} #{header}|#{values}\n") - + if @syslogheader == true && @leefheader == true + sheader = [syslogtime, sysloghost].join(" ") + header = ["LEEF:1.0", vendor, product, version, eventid].join("|") + values = @fields.map {|fieldname| get_value(fieldname, event)}.compact.join(" ") + + @on_event.call(event, "#{sheader} #{header}|#{values}\n") + + elsif @syslogheader == true && @leefheader == false + sheader = [syslogtime, sysloghost].join(" ") + values = @fields.map {|fieldname| get_value(fieldname, event)}.compact.join(" ") + @on_event.call(event, "#{sheader} #{values}\n") + elsif @syslogheader == false && @leefheader == false + values = @fields.map {|fieldname| get_value(fieldname, event)}.compact.join(" ") + @on_event.call(event, "#{values}\n") else + # default behaviour LEEF + header = ["LEEF:1.0", vendor, product, version, eventid].join("|") + values = @fields.map {|fieldname| get_value(fieldname, event)}.compact.join(" ") - header = ["LEEF:1.0", vendor, product, version, eventid].join("|") - values = @fields.map {|fieldname| get_value(fieldname, event)}.compact.join(" ") - - @on_event.call(event, "#{header}|#{values}\n") + @on_event.call(event, "#{header}|#{values}\n") end end @@ -222,7 +242,7 @@ def sanitize_extension_val(value) end def get_value(fieldname, event) - val = event[fieldname] + val = event.get(fieldname) return nil if val.nil? diff --git a/logstash-codec-leef-3.0.1-java.gem.old b/logstash-codec-leef-3.0.1-java.gem.old new file mode 100644 index 0000000000000000000000000000000000000000..7055668af72f0372e4ec32df031f3e358535ef1b GIT binary patch literal 13312 zcmeHtWpG_hlI0UKGqc6a%#0Q@Gx&)uMvGY%Gcz-@^u%B>GqWs~CGFR{KYF%jX7^7| z>}*8mpSqP9HzVuRy(bEegN3V!xrwU@la&|XzsgwtG7b(7z~9=x>>pcJ4t90`D?1A- z8!HDFH#a+gg_WIygB?K1@?TZZzs>9B;%egjS4rQkEiCN+ZQviC|8MdCHMYMG?jK(N z@7g7af(5)z(P)EzE^0ae=UGrcu8d5+6!nMkIEZ3I0a#n=6wh>R=wSm@4!$f84c5n8 zR-N}AXWd&^6w3IR6eaI@-@aVsbh;GK6e!!X8w`1QA+;+ji4Qrjy~`!amb#v^BaT%`V?2o%Sfn= zW#f1n+aL(zn~;&I<-?m`L;@3oA9M_z0!MoMD4?EBmh+Z{!(ZRaK7$^;WZ$g17sY$y z!4b>A)tT}H4|^)9>0_Y0ItALG4@uz9ohhUa8Qq$QdC)!{w|Z9XB1Epn6`!iuo3^cB zy5D2cm;G%l`;bwB)4fM^!lUiw^2xtJ(%~XtQ#yv(vNI8p&M+gYMmQwlaM}YVTTI_) zTz-$9=REl&XP!Lf;Up)f3U^z8d(dP91U z=I~P3B%P}wiiMVn&xl_sKVb*XiNn^v$^MSqp)>5PxPyH+^1FQK1$_j4!%KzihSSE= z5+U1)z5ds!rgjL(O1f~~l}E_J4Q=$++S&8tW8d7zGla5)(|XU=!!IkgMpZv%1Vg`Z z>=+I`^>l7ba_utNv?G?|TUb-nV3MVKhu%2mWbnv4*bECb@-=u;=<=qojxpqXa!vmY zx?Szv7NwIw?#${JL8sMla8s4x@LB>iS#t2N_qbm8agk8^oRZz7GRg8#gobwO9FQcOgB~oW&jeo0O*TlNM5bg%pcaysOG3 zG=iVG!

1cF2WlB|dCn`?|E@pmKe?{|$^CyZ;Qu@RXJh4N`*-}$&c*pJ{{JUW^?#V| z@BDuu`0lqplJK(Z6UnHNS|lGtl6a|&vy|Y#tNC-Kytru@LjxW%m69A)q%Oc*XW{z$ zwPT!PoHNi_*_pku^O;;mw#l5Hw;@LI3Uu+8Oc68X7F=W2E? zdNnjZXvq8B`SV|DzEwV2R&Lq=1wCI~G1h=B{K`G1)wM!{)adzm06Hs->1?XYnu;0a zEAG2h<4mau>r`C3Ivg-=W&7`4Q+|(OmZM>l-wWz58)nTCb|w$4E^3d;$J~|M2^z9< zA0Y`m!Pear(AKcmQ54UMUV^!y6C>fg?R{t*>bL@c^>j`ACWU>O4XK^AIv{I;Oip~) z?RwD9SzfE9Ay*KKCC@Ibn{DV#^2hGvUFe2si!n>bWg0|ShRWhr6v^r~xQjJ3qLgOY zr5|iNKcsOjRo)p&XJ@Tl01^@dNU%}dZos~Em%n5Cka4U=7g^7IjXm>0yfG$< z!&C7aXsa`}4QRIk%OjiWr%(wSB^x+S5o};&hs+?+pf)*)y0n}}>5A9eou5u&y+xYH z>cuxwDyfv8hE5{{#H&z8}jjuf)n%3@z;1>{Hg5;7z ze@Yp8rtDa|M}(1!T{2kL9Pd0~k;%)L(7iUl{!j zd%V4G{H}**V6L~W{mI_9w=P`oUV9)bDeyVMLIL`LQcAr29xo_F=wyT)h6Eqx4+j?1H@m8?gW;NU=yF%d&_9# zr7Hl85&HAba9(LoQma04KOa{rVP_9i=#|Rn_15`JI`hC$U2yyyUt=|dovfevL?$5A zp|mA$)=S~7XFV`tC{!keoj_pSkc%IX=RMpIFbuFWhsRZs{@rWNblp%y?Ng6Z7aLJ@ zBL0CRvXp7Sfj0fwp!)kD&piGh_63SlPUP-HO zGNvks5XSJi_FzYj_^(3`({c+xv;s!eenT=c&3*|t4PZcb3?809@Y0j9L-Y78(Z@rr zkAi{-hfO3#CgF?9ca^&mdvtCM{`4_PQ?@1emC#B-7K=h;HsbTn>!nib?Dd?3r0` z$az@gjQV1MLD~K4irMc5UP?DzqZKQ8RTbmS{`C2pxf#a?-2H02MA=`dSU>vrgmM!4 z>C#_g9Xd$MM!%zenT`1+j0FG&a8a(*Vk^L1F00d9hEfSgG%heG44@zC&nHw%s9lCa zXWRR`6EXd84?tW6Oy3FZm?V6TvCho8vVj8cI{H?uj8_Bk3}7?Z|Rq=xYi!RH5 zh~U$^$`#=QBKl|;t}hz9-`TwD8+%)gnBUE=ccwaXQC5WAw|cidz3W;#XSTYn9PPcE zzt=roG5+zIa^L#+>D&ACsFCeNpvX%~w9*>DkH0U&C&VH5mSqLKoI`MF6NuNoKT7Dr z1?|n`cq_0|$S(%V2I}*o=Y3p2RCR9W58ZeP6SKfUD!oD zuR-*SlK;?%Dt4OE22RX8diHkyJ_Bv?BYqfkf98I3=Q^JDuP!}*|McARcQO_W<(DfS z6ec8wJfgM#jgxSR$XbOXMIO=rLw&W*-iH5lCm>RgLv1dItQ8-d1aHq(|Lw;ICzabM zf4NwqbvL2y0>+9wIU#4E`WgZntfa;YEF$-v?pQ9ZQKD$jglsei)nFf8RU<9;7{{+I z8kVMkn=C~NmPEKB_>?uWOb;tulY){1d~pmX(@=F9gIofFi)1TFTvCd3?MQ=fG-k>U zN!2a<@CtY=VsUtV+=a85V%`%Hlf|{1kgJ)YMHl>-OA@TX@4@sC1SO0N>!C+Zd5aY5 zoG4;_Dp$N2+iXEr^0m2lcss8Ff>%8DfTbd$aMaB(7H((M&hS!V=rKZ5mE=h3-38Va zWLNd5bfV<4NE0;&Hg6`YusU2auOuR7B8)8l1P%}yYW3JAWrKyJC?Gp?6o3>BTdAXF zo%#h#G9?=C4&@6p!+Db>w)VaYCcjY9d~IRr!3i$nbAVpH?>N>4?Z~L}eQ|==I*uco ziY5>7H$oVqMlcemzL`X&S&Mo;M7M9&vq%{23glzZ>b78pI$sXVcH3(HgaF|!pe1rHRsfwY8D=Nc==MmsB>=ukj*n(ztk{d zCYq(||7oE0T3bY8#4rxslt@r2OD&}f1cTH^)Tl7q9G~tpjP5LT-)X-mV)?NIb|Hv{ zo{|P7{af)kqR*g<0sJ?6fWYO@Pl1tFR+I=*XG6L>+rep2Swn^d$oQHfl~Q?Bl1A=2 z-YhBDKb+sZkWug!?s^Y19Ctw+-47Y z+qSje5WKKIg(rSqoJv0MiNogOmH2Cf@;x(bK4485gE&v{jctc!TLHe6K0VNTso!&d z_D`^)*+d!`_}et{wgiNGnig|N1^IRv^el+GY|Ms_6fs%GGE7dPE)(GUVK)@~ zyXK58WG*Mm(sEHA1Ol0=j^Dvy(+!ZP*Vj(YB_L#-_Ckt4q|30XwCD^#->TT;6n-UN zj)RV6{8Hy03Agj9YeIX^CzT0JriBP^M_tci-H#fzNmd4Gd)9^`JCI@zV}p@-)Tq47 z+$~a~Q=9`5%t>fUk#N$3hM;-s_zCFn)oU6ZF2+0jO%A^(704QAMy<^s{B%nwq?apJ zD2}a{ZByE*g5)}1fq{HMW65!h70&z<>V6$TiXUA#0or7gprAVD87(8%a z@^++oSil6A8??kAIBBSWeZdP^(P<%ktO)J2Zt;$5!Y*q%X)KM>aRE=ng5U^9L)c_E z2z_ZS!+_hW@vwu=!aCO!vIr3`aL|x4Wec2hsQkQ~>>3pDi7|6H)m;Fh?T=vnsJ;j1 z^?Zf%)saiG%PWqfS$#$p_atNNo4WiUE?!NgY6}L+{TJoDZQotzUyHKRx`BO-NlcQf z$r%XcRh0J8YcQ8`^cXTFd92?>Xns3nx1)jv*jucaIF$UX6qHce0I^2^aeRp7N{T)f zKr-gbL8nE{Y3@o{y+3@Hld)1MT`9Qly5*h>Hg#Q`NaabP2w@4#N#20yz9slN%MHg^ zeEi6nD}Fl{G5@n`Ku8^gbzCyk5qia#$$b9QL={;aX`45#V1m60%Ny-kjk2V9+d#{Y z@=BJTCWm{K1@T<3Q7B}^L?5sKjLcp~Q?ky~D$k7gWZi-xSfS{~xW_HO@73b^E;}B< zN0{)QvkFgKC4=}ONK1w%1ipmc@qDzq5d=y*gwq%OJM1t1eA%Tpg6E%}4U2}LPobZm zVGYi-=lt-}F}3n?3RGOlmQjJUeIk*S{%ARwue3Mus3q`X1edfb&`$7mn6Qo)>}p@g zEZonv7izD+8(wzxDv>`SsEvlFBQv$cUxcD%M;dEkD4rjmZ+B=v-ppq?24|bT zguBn%3lj*~edmh-&9vyoFrJ@V#RRsG5$FY1CoFnS@@Hn(W~$X`PL^aDl9Vo|-k{*p@>7jUF z0C$NH9o6M}fuq{Y#Qt6zb8*{rk#BcT;}Qu%akHr_3L!5Y-@N862;qF3IY zL;PGM$16Gw*IrLaWd=y#wdVRKD0uj>?>FJMpxe4?YWQLkR5I2GXGirG(Vq~~D06QT zE})+nOg|uL4PrgIl6iE@OI01A%DL_YNHg+EVIc!0xbeUHsE+<3TtEyFOBq zfj&0Zt@UKfq;8C&rIX*G0e=%4(?3)+cA6=T$0yT zkEdasA}wbG$4>u!M^kR(%w|3uZc@t!(h65ZT6`pb?uD+tbQW4rm%`_nDE447IZ3kz zM)5d5hwhbvrmhbpFiRE*_?oEZU{dHFr9m}ioP}>90S3EH<>8EohQh|_YxKsQxC&@d zW|K#8ZCe@_rd1Q|+R~P~he`}Ni{{yRruvLlja)cGqZ$@`(@A+5@ZNpu=#bd6V{#go zL5Fvd{B7>ZlhIhD8y_!Ij^VeJM0umgk4j4>%YpgQKSjzi(`ZIQygPf4(Y%AO(C6W9 zE#4Z}1rL#~HrL%&^%XoTyl+V(L>v6ozlK{|+t@4VIS6yW3}KT1fDG5KB7IcvHh!vf_Et@ zWn#kBWuYP?M15OODVRAJ#e3Ch$}ofTHOK*0!gcJ-LEV6j*(#yWBb08#W|-Wy!Zj11 z`+`K6TAGSQaLlC|6AhB%C!vx8iFtXUs*3qJ#> zEGr|B@h4V0KQi?~_?VOw+s}ZwS)1T`Od-O;rueVGEP?PxGB3IQ5^!|hJGS66(Ne{PtV% zg7BYZ^pR_?w0itQt9bTdWMizv5Xay(Xb_2JDg;YwGTO&=LDcx~EWpFE9C|4i9-|7x zai81x=wZpcq?q90xE&D+mU`8OW>HKE_Y>le%4L4?P!abuS>%K&Q66f+Meco^8TZO$ zo#K+!cPm+{;j^K3h?k-eam*9~Gc=?MMG+_HjYtS;DnW+R2fAkP zy2N-F6^mP2k$tyO(U=J>h)g38;l0m;ZSc@Vd@ymU5y^#Ahp=w0i-^T;Bx>_oW^jhO zJ_4J)(Ri*QV4yksI3t8rE%48uCf{zE)8r;)Ff1t<7&ihE%VXUL%->b2T{Ai%8cBv< zk*HKQk`tn&9Nt4a$wZR>I$@~=ztFA9Tu|tNAmFJBb9&{adk-YCohsa^szbQd4La&Y z-Qq%TQ_WDDw8G#&7yz9^?*Zb_@iVk(IGYJYUnf?A=wz&y7CACgg{(rVTDa~TRrc{l?;P%TFXThQORRW>SAL2zeg`oL! zwZQ5#D&m~ZZ3#c4?W#R%@_@{zgta(CH2tK>K4I)&F44u4tm*qEVI75BgplzEd(N!M zDt%g+RbDIn=XlcoHEx++_PBX9QZmiCD}^c#L9$CarCi*5WcLz}@zQkNn;oNwn|s;S zB3)qUB(_+t=8p3j`gN;t#;g+o)H@e!`IE>jFvZ&^QOJ&NiV2+g67Jrz>5rmgC-#MD z7ssxAdBg||DxPW*$r;uV`3jTUT)OOs5gDft57B>!*bh(BWaU+VckN7%l4_N)9+?>F zE{7d93D^3#mR;I3NR7EY0equaA|PB@3*25r+`kSVctYk7@21+m>;?!DHiQ9NNIu%$ z9eefXtLK(st3x87U!=EEAs%J%CQk9rIMm;<*O$;+FZ5C^B8(Z7vLHd^iyQ0s}>`> z(uxKw9Z9DOs*2CQ@Od*vA%hLUpm$-x7KI5Wy|~-VV0?12W!t-o@~hqCQ|HgfIM=o5 z+17L@OgB#VEJE4FQu4dDhPW&${`wt5butrFT3U+sLx^f|uOl2yiNHqQ%!t_8)o=}< zBzEj{B98xdzvC~3>z9e`t-CPx3L}=Tt9l>C7aHZ=G^=g;PGbR_72Zv9>_|h=Lz#@2_B> zpqB13bcw8;X$m*ff&}yGNXRSKdRx4Q{-b_K+Jiw@qmy1eXbfVgXAPG?4J-{?w~yDz4^OVg4fm$ zq>2{N=ZdTdNR0QfrSa+Z19PGX&Q`_ zkxspF^5Ysfs+U3HDKP{$Q8$uXC89m<80W^jxj|Ip)>9_{75w;X^NhcU<~_P*4Q#f( zQ1&;a5P$GAbXZ(xw8e5X0qY8O$^Dtyi|lQzkY0YTHU&!hLs=U4xnc4_lH(;T|FM0v zU#Bay2Pp{j@Hs2@ke|JN@_ygVlS|Rsb_inAf?=A{? zl{daXxTTEs&I!BiMSo<=yUh(d#g3OA;n^~?ztD*>)7FlYes0%wAR{x}49{c&JoJb8f=NH*qlR1og4aU3!^~O%oR#Zsn3-opE@D*Xo zD1KxtR6P{!jRnZo2^G~yH&6Pl7+*L0$K?blS;$k#3ew{0m_tN{k(Rv^Znemdhr33uCKqHraBa2gb`kwhN_C=x>73oc2ueM zabnq4qTH6Z-1~Xzoby|TtNonDzHFqVecSp7;#D|i~i715OpVmZ9&Ql$bXP1|KtBC0aZlXA9i;%*)jM0<^#5bh`+2k(*EwaObp{SC;~89ho4`FL2JwA`<@D9X z$dHrX%1mk((qM>|ZNyVA(V3<&`@(e3p?dqv)5ioGz?x@{=e;^%~5l8m`A4&OckVE}YE3Iof_jHQ- zQDkI?B)sT5eWTdDi_}8}?5Ut3L_RTe9RdU5UD-)s%8l^s_&u07-qzA-&N%k1hG#yj zB7e0rTv9iMzM`tTmWq|7MJdPGk;@fwPR5eDKSO4h|=(zH`|$p$%z6B4SfLs4c~WQz&96y<|- zu5z99_ip$X+ncu_BH~j%f)N!w%(4pU5`h7FVRkyl^#~ZNUxutr%6ET#alNrMcz@W; zY*8PlxH~S`h@=>%56V-dbErA{`w+*QCslrfiAQI@%7AmGi2|J~`gao)Z}B~elz{}* zIk7a4d-0~qBbf70{`N{PCZCvJcUC4KURp90n8N*%vAy zSa%jQNo?`?2bW)&V{J!HEgA&iIF9HNM~!O8;f4?C{EQGNeRP2vn( zldQ$ZVtU8y1uXE5Lz+mgy@*a`K+5{DabCPaTd9Z7D=`T=9fW)fw>nK)*L3fkdKG;; zcD2%bR^|BTP)|Autc+tfUmmWT`#=75m~o%ks92 zZP>8>Cv;B5uaLYd;PDq?SMNZ@G6kYVfIziSM}xq#>4NlhD$l)sH*~k577n8U?BN}^ z#ZuEj0l!{QCfa*}iaZWIg1aZ@ZGv(qgZSH^28|&n@#4oyRpaAVca8iS%K-2zwWh-B zH6=F3+|hLl|4sj=rMv(H&RhtQ%W#V4+Qq2zna{g3tdUenn4_0>-TlFhlCI-Q8d{GS zi=t33B9wU-fsQM~B<7v2R6ETs_SM5{A3TJo{X?XsW>SKa9tK-5+m)TDvZg`J{ndVd z-1V43;bS+gEolR5Z~sJ4N1u#rbwWlpC5(`@?k3ZuYsCa-85$Kdn>-PMCiuL|SmboS zsdgKF*G|jsrcfy4*N+!%*ff)2+dgl}(E_w)ww^}Q@Wx~?_b7n77Wnd&y(OUknoY>^ z*mT@7%igkK`4NUYqXvA726sT42l1$X(<5oHa1szEEm^1GbsQ6Dq;DBuq>oKbd>n0g zM{!K`^@!soMB?igFif7vg-f|#*2urk|GKB1a+%G;#PNX&(Cx`r$=E(sahmeY346m| zctW5RGdutjCsOa$Mq)8ueAdiq_=d49e&YKBe6UTUt+nUvco)avv$&JQ(k^Kqk+JK@ z{ED~wZ}+Z3UA#iPqV*CAq*D_d_IO2bBkI?H>?~^?8f`#2LdfKyVtjiG!*~v9PZ9?> zgHS&kU4WXs$G!P&Bxx`|z?0g8sX2l2BBx5<>4!3B61*|Cu3Y2du3OaCiyG)#t|A6m@;F9FF|@}LIJD@)L`6$<)>mljYBmq zvDINTTQ}Km{4cGDxG+sxH^CxXc6(!Q-NN8V)1`acf1SNOFnG zG6+V70DAbjkn8&oklY;F1Zwa`F3U7pd5YTYtQEOsc;mPMN|fAIE*Oe}HneNPMz^eu zlCe5VM`8ItHlJ?U6(XEin;3m)`Vdo8G|U{4rs)pAPO6rLosNcaR1Zq{o1ugR@}@n> z`L9=P3(Qy<7pzb9pr9(1D5#r!!>F}_;Ql)EHi%kIxiKWZ)fh`&x8~k3KBPZ62Y7{B zIt$OnXh-?N@1A}YEn(4i7oRhw!^!uj%Ey@#GvHk+wUA;{uaOU>O=Ese69-DQ?zG)r zTEJE`Bpv=@+^5c~&H9eKsGJB4=)x9B9{$-Dl)amJyHQzcJs7s>S!t0A z^y;bk9t;3SnNhIu3|pJ-a_esBtKSUdPglpq__{ADYhU4`{M6vyWwB9x*tk%A&{-L7 zj;AP}rW|hf+Ba&xCgqx2MrzIJ6WAlTFAJo1E*xf5Fgr*XcIV!;RaI1_@Fh`xXz{2Y zV7a@VZI;%$p8xT4{&|$$#>`2!DCsLsyoZsqrhq&89N)DIe=TPuCKvNLMO$_)wDi{E z_!&fhxmC0ky>wiNeWM9FgFi=S6lq-j`%sqsxcGCA$AMpgcG0d(+o8EmPTFNoV z=eq0bfdDZ3RI6rbh=5@6!x?xm+v{)>H+hbZ}sf;mR zQ703p9TRoT>-jVW_4EYv=V7g3jE&`05q)B3$RP!6TpBf{Z-UzZnk$xtArPlk2XLZ7 zUrsS@rwxg4#>Q=ZOga2YUh!b{uH%0-cKiwXm$2va69P~@G6)Np{0~(=|GCr5+QQ7v z#m&Km$@O*>A(K-S^MWj{;vPBh^J4{6GfD0 z*V;wmDWz)mvm6{~1b^qFF^~PKnR^_FQKRQ39|zihJU@mJ06x9tdP;)m{r-Hsb#W^~ zngFvXw~i?*Dsw1A#nv6AgGjpDn2)e>jR@1yX3Ht33=D`TbXsz%lV`6$-}$e<(?fhL z%j3zS*Ti%a!iDPHnsfJ!pCDDcZSG`? literal 0 HcmV?d00001 diff --git a/logstash-codec-leef.gemspec b/logstash-codec-leef.gemspec index 085ee4f..e029e4d 100644 --- a/logstash-codec-leef.gemspec +++ b/logstash-codec-leef.gemspec @@ -1,7 +1,8 @@ Gem::Specification.new do |s| s.name = 'logstash-codec-leef' - s.version = '1.0.1' + s.version = '3.0.1' + s.platform = 'java' s.licenses = ['Apache License (2.0)'] s.summary = "LEEF codec to parse and encode LEEF formated logs" s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program" @@ -20,7 +21,7 @@ Gem::Specification.new do |s| s.metadata = { "logstash_plugin" => "true", "logstash_group" => "codec" } # Gem dependencies - s.add_runtime_dependency "logstash-core-plugin-api", "~> 1.0" + s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99" s.add_development_dependency 'logstash-devutils' end diff --git a/spec/codecs/leef_spec.rb b/spec/codecs/leef_spec.rb index d24268d..8d4aafc 100644 --- a/spec/codecs/leef_spec.rb +++ b/spec/codecs/leef_spec.rb @@ -213,23 +213,23 @@ def validate(e) insist { e.is_a?(LogStash::Event) } - insist { e['leef_version'] } == "1.0" - insist { e['leef_device_version'] } == "1.0" - insist { e['leef_eventid'] } == "100" + insist { e.get('leef_version') } == "1.0" + insist { e.get('leef_device_version') } == "1.0" + insist { e.get('leef_eventid') } == "100" end it "should parse the leef headers" do subject.decode(message) do |e| validate(e) - ext = e['leef_ext'] - insist { e["leef_vendor"] } == "security" - insist { e["leef_product"] } == "threatmanager" + ext = e.get('leef_ext') + insist { e.get("leef_vendor") } == "security" + insist { e.get("leef_product") } == "threatmanager" end end it "should parse the leef body" do subject.decode(message) do |e| - ext = e['leef_ext'] + ext = e.get('leef_ext') insist { ext['src'] } == "10.0.0.192" insist { ext['dst'] } == "12.121.122.82" insist { ext['spt'] } == "1232" @@ -240,7 +240,7 @@ def validate(e) it "should be OK with no extension dictionary" do subject.decode(no_ext) do |e| validate(e) - insist { e["leef_ext"] } == nil + insist { e.get("leef_ext") } == nil end end @@ -248,8 +248,8 @@ def validate(e) it "should be OK with missing LEEF headers (multiple pipes in sequence)" do subject.decode(missing_headers) do |e| validate(e) - insist { e["leef_vendor"] } == "" - insist { e["leef_product"] } == "" + insist { e.get("leef_vendor") } == "" + insist { e.get("leef_product") } == "" end end @@ -263,7 +263,7 @@ def validate(e) let (:escaped_pipes) { 'LEEF:1.0|security|threatmanager|1.0|100|moo=this\|has an escaped pipe' } it "should be OK with escaped pipes in the message" do subject.decode(escaped_pipes) do |e| - ext = e['leef_ext'] + ext = e.get('leef_ext') insist { ext['moo'] } == 'this\|has an escaped pipe' end end @@ -271,7 +271,7 @@ def validate(e) let (:pipes_in_message) {'LEEF:1.0|security|threatmanager|1.0|100|moo=this|has an pipe'} it "should be OK with not escaped pipes in the message" do subject.decode(pipes_in_message) do |e| - ext = e['leef_ext'] + ext = e.get('leef_ext') insist { ext['moo'] } == 'this|has an pipe' end end @@ -279,7 +279,7 @@ def validate(e) let (:escaped_equal_in_message) {'LEEF:1.0|security|threatmanager|1.0|100|moo=this \=has escaped \= equals\='} it "should be OK with escaped equal in the message" do subject.decode(escaped_equal_in_message) do |e| - ext = e['leef_ext'] + ext = e.get('leef_ext') insist { ext['moo'] } == 'this =has escaped = equals=' end end @@ -287,11 +287,11 @@ def validate(e) let (:escaped_backslash_in_header) {'LEEF:1.0|secu\\\\rity|threat\\\\manager|1.\\\\0|10\\\\0|'} it "should be OK with escaped backslash in the headers" do subject.decode(escaped_backslash_in_header) do |e| - insist { e["leef_version"] } == '1.0' - insist { e["leef_vendor"] } == 'secu\\rity' - insist { e["leef_product"] } == 'threat\\manager' - insist { e["leef_device_version"] } == '1.\\0' - insist { e["leef_eventid"] } == '10\\0' + insist { e.get("leef_version") } == '1.0' + insist { e.get("leef_vendor") } == 'secu\\rity' + insist { e.get("leef_product") } == 'threat\\manager' + insist { e.get("leef_device_version") } == '1.\\0' + insist { e.get("leef_eventid") } == '10\\0' end end @@ -299,37 +299,37 @@ def validate(e) it "should be OK with escaped backslash in the headers (edge case: escaped slash in front of pipe)" do subject.decode(escaped_backslash_in_header_edge_case) do |e| validate(e) - insist { e["leef_vendor"] } == 'security\\|' - insist { e["leef_product"] } == 'threatmanager\\' + insist { e.get("leef_vendor") } == 'security\\|' + insist { e.get("leef_product") } == 'threatmanager\\' end end # let (:escaped_pipes_in_header) {'LEEF:1.0|secu\\|rity|threatmanager\\||1.\\|0|10\\|0|'} # it "should be OK with escaped pipes in the headers" do # subject.decode(escaped_pipes_in_header) do |e| - # insist { e["leef_version"] } == '0' - # insist { e["leef_vendor"] } == 'secu|rity' - # insist { e["leef_product"] } == 'threatmanager|' - # insist { e["leef_device_version"] } == '1.|0' - # insist { e["leef_eventid"] } == '10|0' + # insist { e.get("leef_version") } == '0' + # insist { e.get("leef_vendor") } == 'secu|rity' + # insist { e.get("leef_product") } == 'threatmanager|' + # insist { e.get("leef_device_version") } == '1.|0' + # insist { e.get("leef_eventid") } == '10|0' # end # end let (:escaped_pipes_in_header) {'LEEF:1.0|secu\\|rity|threatmanager\\||1.\\|0|10\\|0|'} it "should be OK with escaped pipes in the headers" do subject.decode(escaped_pipes_in_header) do |e| - insist { e["leef_version"] } == '1.0' - insist { e["leef_vendor"] } == 'secu|rity' - insist { e["leef_product"] } == 'threatmanager|' - insist { e["leef_device_version"] } == '1.|0' - insist { e["leef_eventid"] } == '10|0' + insist { e.get("leef_version") } == '1.0' + insist { e.get("leef_vendor") } == 'secu|rity' + insist { e.get("leef_product") } == 'threatmanager|' + insist { e.get("leef_device_version") } == '1.|0' + insist { e.get("leef_eventid") } == '10|0' end end let (:escaped_backslash_in_message) {'LEEF:1.0|security|threatmanager|1.0|100|moo=this \\\\has escaped \\\\ backslashs\\\\'} it "should be OK with escaped backslashs in the message" do subject.decode(escaped_backslash_in_message) do |e| - ext = e['leef_ext'] + ext = e.get('leef_ext') insist { ext['moo'] } == 'this \\has escaped \\ backslashs\\' end end @@ -338,7 +338,7 @@ def validate(e) it "should be OK with equal in the headers" do subject.decode(equal_in_header) do |e| validate(e) - insist { e["leef_product"] } == "threatmanager=equal" + insist { e.get("leef_product") } == "threatmanager=equal" end end @@ -346,7 +346,7 @@ def validate(e) it "Should detect headers before LEEF starts" do subject.decode(syslog) do |e| validate(e) - insist { e['syslog'] } == 'Syslogdate Sysloghost' + insist { e.get('syslog') } == 'Syslogdate Sysloghost' end end end @@ -366,11 +366,11 @@ def validate(e) event = LogStash::Event.new("leef_vendor" => "vendor", "leef_product" => "product", "leef_device_version" => "2.0", "leef_eventid" => "eventid", "foo" => "bar") codec.encode(event) codec.decode(results.first) do |e| - expect(e['leef_vendor']).to be == event['leef_vendor'] - expect(e['leef_product']).to be == event['leef_product'] - expect(e['leef_device_version']).to be == event['leef_device_version'] - expect(e['leef_eventid']).to be == event['leef_eventid'] - expect(e['leef_ext']['foo']).to be == event['foo'] + expect(e.get('leef_vendor')).to be == event.get('leef_vendor') + expect(e.get('leef_product')).to be == event.get('leef_product') + expect(e.get('leef_device_version')).to be == event.get('leef_device_version') + expect(e.get('leef_eventid')).to be == event.get('leef_eventid') + expect(e.get('[leef_ext][foo]')).to be == event.get('foo') end end end