nginx

Paddy 2015-06-22

0:68478c1bddde Go to Latest

nginx/jwt-lib/basexx.lua

First basic pass at JWT auth. Mostly just a fork of https://github.com/ficusio/openresty, with a few twists: * We've narrowed down some of the configuration options, and we're passing more headers (essentially exposing all the data in the JWT as headers). * We no longer automatically return a 401 unauthorized if the JWT verification fails; we just don't assign it the headers. The consuming service can decide whether or not they want to accept the request. * We automatically fail the verification of a JWT if the token has expired in the last minute (or shouldn't be used for the next minute). If the token has expired, we return a 401 that our clients can catch and use a refresh token automatically from. If the token can't be used for another minute, we quietly just refuse to add auth headers to the request.

History
1 ------------------------------------------------------------------------------------------------------------------------
2 -- util functions
3 ------------------------------------------------------------------------------------------------------------------------
5 function divide_string( str, max, fillChar )
6 fillChar = fillChar or ""
7 local result = {}
9 local start = 1
10 for i = 1, #str do
11 if i % max == 0 then
12 table.insert( result, str:sub( start, i ) )
13 start = i + 1
14 elseif i == #str then
15 table.insert( result, str:sub( start, i ) )
16 end
17 end
19 return result
20 end
22 function number_to_bit( num, length )
23 local bits = {}
25 while num > 0 do
26 local rest = math.fmod( num, 2 )
27 table.insert( bits, rest )
28 num = ( num - rest ) / 2
29 end
31 while #bits < length do
32 table.insert( bits, "0" )
33 end
35 return string.reverse( table.concat( bits ) )
36 end
38 ------------------------------------------------------------------------------------------------------------------------
40 local basexx = {}
42 ------------------------------------------------------------------------------------------------------------------------
43 -- base2(bitfield) decode and encode function
44 ------------------------------------------------------------------------------------------------------------------------
46 local bitMap = { o = "0", i = "1", l = "1" }
48 function basexx.from_bit( str )
49 str = string.lower( str )
50 str = str:gsub( '[ilo]', function( c ) return bitMap[ c ] end )
51 return ( str:gsub( '........', function ( cc )
52 return string.char( tonumber( cc, 2 ) )
53 end ) )
54 end
56 function basexx.to_bit( str )
57 return ( str:gsub( '.', function ( c )
58 local byte = string.byte( c )
59 local bits = {}
60 for i = 1,8 do
61 table.insert( bits, byte % 2 )
62 byte = math.floor( byte / 2 )
63 end
64 return table.concat( bits ):reverse()
65 end ) )
66 end
68 ------------------------------------------------------------------------------------------------------------------------
69 -- base16(hex) decode and encode function
70 ------------------------------------------------------------------------------------------------------------------------
72 function basexx.from_hex( str )
73 return ( str:gsub( '..', function ( cc )
74 return string.char( tonumber( cc, 16 ) )
75 end ) )
76 end
78 function basexx.to_hex( str )
79 return ( str:gsub( '.', function ( c )
80 return string.format('%02X', string.byte( c ) )
81 end ) )
82 end
84 ------------------------------------------------------------------------------------------------------------------------
85 -- generic function to decode and encode base32/base64
86 ------------------------------------------------------------------------------------------------------------------------
88 local function from_basexx( str, alphabet, bits )
89 local result = {}
90 for i = 1, #str do
91 local c = string.sub( str, i, i )
92 if c ~= '=' then
93 local index = string.find( alphabet, c )
94 table.insert( result, number_to_bit( index - 1, bits ) )
95 end
96 end
98 local value = table.concat( result )
99 local pad = #value % 8
100 return basexx.from_bit( string.sub( value, 1, #value - pad ) )
101 end
103 local function to_basexx( str, alphabet, bits, pad )
104 local bitString = basexx.to_bit( str )
106 local chunks = divide_string( bitString, bits )
107 local result = {}
108 for key,value in ipairs( chunks ) do
109 if ( #value < bits ) then
110 value = value .. string.rep( '0', bits - #value )
111 end
112 local pos = tonumber( value, 2 ) + 1
113 table.insert( result, alphabet:sub( pos, pos ) )
114 end
116 table.insert( result, pad )
117 return table.concat( result )
118 end
120 ------------------------------------------------------------------------------------------------------------------------
121 -- rfc 3548: http://www.rfc-editor.org/rfc/rfc3548.txt
122 ------------------------------------------------------------------------------------------------------------------------
124 local base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
126 function basexx.from_base32( str )
127 return from_basexx( string.upper( str ), base32Alphabet, 5 )
128 end
130 function basexx.to_base32( str )
131 return to_basexx( str, base32Alphabet, 5, ({ '', '======', '====', '===', '=' })[ #str % 5 + 1 ] )
132 end
134 ------------------------------------------------------------------------------------------------------------------------
135 -- crockford: http://www.crockford.com/wrmg/base32.html
136 ------------------------------------------------------------------------------------------------------------------------
138 local crockfordAlphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
139 local crockfordMap = { O = "0", I = "1", L = "1", U = "V" }
141 function basexx.from_crockford( str )
142 str = string.upper( str )
143 str = str:gsub( '[ILOU]', function( c ) return crockfordMap[ c ] end )
144 return from_basexx( str, crockfordAlphabet, 5 )
145 end
147 function basexx.to_crockford( str )
148 return to_basexx( str, crockfordAlphabet, 5, "" )
149 end
151 ------------------------------------------------------------------------------------------------------------------------
152 -- base64 decode and encode function
153 ------------------------------------------------------------------------------------------------------------------------
155 local base64Alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
157 function basexx.from_base64( str )
158 return from_basexx( str, base64Alphabet, 6 )
159 end
161 function basexx.to_base64( str )
162 return to_basexx( str, base64Alphabet, 6, ({ '', '==', '=' })[ #str % 3 + 1 ] )
163 end
165 ------------------------------------------------------------------------------------------------------------------------
167 return basexx