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.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/jwt-lib/basexx.lua	Mon Jun 22 00:42:40 2015 -0400
     1.3 @@ -0,0 +1,167 @@
     1.4 +------------------------------------------------------------------------------------------------------------------------
     1.5 +-- util functions
     1.6 +------------------------------------------------------------------------------------------------------------------------
     1.7 +
     1.8 +function divide_string( str, max, fillChar )
     1.9 +   fillChar = fillChar or ""
    1.10 +   local result = {}
    1.11 +
    1.12 +   local start = 1
    1.13 +   for i = 1, #str do
    1.14 +      if i % max == 0 then
    1.15 +         table.insert( result, str:sub( start, i ) )
    1.16 +         start = i + 1
    1.17 +      elseif i == #str then
    1.18 +         table.insert( result, str:sub( start, i ) )
    1.19 +      end
    1.20 +   end
    1.21 +
    1.22 +   return result
    1.23 +end
    1.24 +
    1.25 +function number_to_bit( num, length )
    1.26 +   local bits = {}
    1.27 +
    1.28 +   while num > 0 do
    1.29 +      local rest = math.fmod( num, 2 )
    1.30 +      table.insert( bits, rest )
    1.31 +      num = ( num - rest ) / 2
    1.32 +   end
    1.33 +
    1.34 +   while #bits < length do
    1.35 +      table.insert( bits, "0" )
    1.36 +   end
    1.37 +
    1.38 +   return string.reverse( table.concat( bits ) )
    1.39 +end
    1.40 +
    1.41 +------------------------------------------------------------------------------------------------------------------------
    1.42 +
    1.43 +local basexx = {}
    1.44 +
    1.45 +------------------------------------------------------------------------------------------------------------------------
    1.46 +-- base2(bitfield) decode and encode function
    1.47 +------------------------------------------------------------------------------------------------------------------------
    1.48 +
    1.49 +local bitMap = { o = "0", i = "1", l = "1" }
    1.50 +
    1.51 +function basexx.from_bit( str )
    1.52 +   str = string.lower( str )
    1.53 +   str = str:gsub( '[ilo]', function( c ) return bitMap[ c ] end )
    1.54 +   return ( str:gsub( '........', function ( cc )
    1.55 +               return string.char( tonumber( cc, 2 ) )
    1.56 +            end ) )
    1.57 +end
    1.58 +
    1.59 +function basexx.to_bit( str )
    1.60 +   return ( str:gsub( '.', function ( c )
    1.61 +               local byte = string.byte( c )
    1.62 +               local bits = {}
    1.63 +               for i = 1,8 do
    1.64 +                  table.insert( bits, byte % 2 )
    1.65 +                  byte = math.floor( byte / 2 )
    1.66 +               end
    1.67 +               return table.concat( bits ):reverse()
    1.68 +            end ) )
    1.69 +end
    1.70 +
    1.71 +------------------------------------------------------------------------------------------------------------------------
    1.72 +-- base16(hex) decode and encode function
    1.73 +------------------------------------------------------------------------------------------------------------------------
    1.74 +
    1.75 +function basexx.from_hex( str )
    1.76 +   return ( str:gsub( '..', function ( cc )
    1.77 +               return string.char( tonumber( cc, 16 ) )
    1.78 +            end ) )
    1.79 +end
    1.80 +
    1.81 +function basexx.to_hex( str )
    1.82 +   return ( str:gsub( '.', function ( c )
    1.83 +               return string.format('%02X', string.byte( c ) )
    1.84 +            end ) )
    1.85 +end
    1.86 +
    1.87 +------------------------------------------------------------------------------------------------------------------------
    1.88 +-- generic function to decode and encode base32/base64
    1.89 +------------------------------------------------------------------------------------------------------------------------
    1.90 +
    1.91 +local function from_basexx( str, alphabet, bits )
    1.92 +   local result = {}
    1.93 +   for i = 1, #str do
    1.94 +      local c = string.sub( str, i, i )
    1.95 +      if c ~= '=' then
    1.96 +         local index = string.find( alphabet, c )
    1.97 +         table.insert( result, number_to_bit( index - 1, bits ) )
    1.98 +      end
    1.99 +   end
   1.100 +
   1.101 +   local value = table.concat( result )
   1.102 +   local pad = #value % 8
   1.103 +   return basexx.from_bit( string.sub( value, 1, #value - pad ) )
   1.104 +end
   1.105 +
   1.106 +local function to_basexx( str, alphabet, bits, pad )
   1.107 +   local bitString = basexx.to_bit( str )
   1.108 +
   1.109 +   local chunks = divide_string( bitString, bits )
   1.110 +   local result = {}
   1.111 +   for key,value in ipairs( chunks ) do
   1.112 +      if ( #value < bits ) then
   1.113 +         value = value .. string.rep( '0', bits - #value )
   1.114 +      end
   1.115 +      local pos = tonumber( value, 2 ) + 1
   1.116 +      table.insert( result, alphabet:sub( pos, pos ) )
   1.117 +   end
   1.118 +
   1.119 +   table.insert( result, pad )
   1.120 +   return table.concat( result )   
   1.121 +end
   1.122 +
   1.123 +------------------------------------------------------------------------------------------------------------------------
   1.124 +-- rfc 3548: http://www.rfc-editor.org/rfc/rfc3548.txt
   1.125 +------------------------------------------------------------------------------------------------------------------------
   1.126 +
   1.127 +local base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
   1.128 +
   1.129 +function basexx.from_base32( str )
   1.130 +   return from_basexx( string.upper( str ), base32Alphabet, 5 )
   1.131 +end
   1.132 +
   1.133 +function basexx.to_base32( str )
   1.134 +   return to_basexx( str, base32Alphabet, 5, ({ '', '======', '====', '===', '=' })[ #str % 5 + 1 ] )
   1.135 +end
   1.136 +
   1.137 +------------------------------------------------------------------------------------------------------------------------
   1.138 +-- crockford: http://www.crockford.com/wrmg/base32.html
   1.139 +------------------------------------------------------------------------------------------------------------------------
   1.140 +
   1.141 +local crockfordAlphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
   1.142 +local crockfordMap = { O = "0", I = "1", L = "1", U = "V" }
   1.143 +
   1.144 +function basexx.from_crockford( str )
   1.145 +   str = string.upper( str )
   1.146 +   str = str:gsub( '[ILOU]', function( c ) return crockfordMap[ c ] end )
   1.147 +   return from_basexx( str, crockfordAlphabet, 5 )
   1.148 +end
   1.149 +
   1.150 +function basexx.to_crockford( str )
   1.151 +   return to_basexx( str, crockfordAlphabet, 5, "" )
   1.152 +end
   1.153 +
   1.154 +------------------------------------------------------------------------------------------------------------------------
   1.155 +-- base64 decode and encode function
   1.156 +------------------------------------------------------------------------------------------------------------------------
   1.157 +
   1.158 +local base64Alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
   1.159 + 
   1.160 +function basexx.from_base64( str )
   1.161 +   return from_basexx( str, base64Alphabet, 6 )
   1.162 +end
   1.163 +
   1.164 +function basexx.to_base64( str )
   1.165 +   return to_basexx( str, base64Alphabet, 6, ({ '', '==', '=' })[ #str % 3 + 1 ] )
   1.166 +end
   1.167 +
   1.168 +------------------------------------------------------------------------------------------------------------------------
   1.169 +
   1.170 +return basexx