vADC Docs

Authentication Overlay Libraries - making auth (even) easier...

by aidan.clarke on ‎04-28-2013 03:00 PM - edited on ‎07-08-2015 03:56 PM by PaulWallace (1,948 Views)

Following is a library that I am working on that has one simple design goal: Make it easier to do authentication overlay with Stingray.

 

I want to have the ability to deploy a configuration that uses a single line to input an authentication element (basic auth or forms based) that takes the name of an authenticator, and uses a simple list to define what resources are protected and which groups can access them.

 

Below is the beginning of this library.  Once we have better code revision handling in splash (hint hint Owen Garrett!! ) I will move it to something more re-usable.  Until then, here it is.

 

As always, comments, suggestions, flames or gifts of mutton and mead most welcome...

 

The way I want to call it is like this:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import lib_auth_overlay as aaa;
 
# Here we challenge for user/pass
$userpasswd = aaa.promptAuth401();
 
# extract the entered username / password into variables for clarity
$username = $userpasswd[0];
$password = $userpasswd[1];
 
# Here we authenticate check that the user is a member of the listed group
# We are using the "user_ldap" authenticator that I set up against my laptop.snrkl.org
# AD domain controller.
$authResult = aaa.doAuthAndCheckGroup("user_ldap", $username, $password, "CN=staff,CN=Users,DC=laptop,DC=snrkl,DC=org");
 
# for convienience we will tell the user the result of their Auth in an http response
aaa.doHtmlResponse.200("Auth Result:" . $authResult );

 

here is the lib_auth_overlay that is referenced in the above element.  Please note the promptAuthHttpForm() sub routine is not yet finished...

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
sub doHtmlResponse.200 ($message){
 
   http.sendResponse(
 
      "200 OK",
 
      "text/html",
 
      $message,
 
      ""
 
      );
}
 
sub challengeBasicAuth( $errorMessage, $realm){
 
   http.sendResponse(
 
      "401 Access Denied",
 
      "text/html",
 
      $errorMessage,
 
      "WWW-Authenticate: Basic realm=\"" . $realm ."\"");
 
}
 
sub basicAuthExtractUserPass($ah){ #// $ah is $authHeader,
 
      $enc = string.skip( $ah, 6 );
 
      $up = string.split(string.base64decode( $enc ), ":");
 
      return $up;
 
   }
 
sub doAuthAndGetGroups ($authenticator, $u, $p){
 
   $auth = auth.query( $authenticator, $u, $p );
 
   if( $auth['Error'] ) {
 
      log.error( "Error with authenticator " . $authenticator . ": " . $auth['Error'] );
 
      return "Authentication Error";
 
   } else if( !$auth['OK'] ) { #//Auth is not OK
 
      # Unauthorised
 
      log.warn("Access Denied - invalid username or password for user: \"" . $u . "\"" );
 
      return "Access Denied - invalid username or password";
 
   } else if ( $auth['OK'] ){
 
      log.info("Authenticated \"" . $u . "\" successfully at " . sys.localtime.format( "%a, %d %b %Y %T EST" ));
 
      return $auth['memberOf'];
 
   }
 
}
 
sub doAuthAndCheckGroup ($authenticator, $u, $p, $g){
 
   $auth = auth.query( $authenticator, $u, $p );
 
   if( $auth['Error'] ) {
 
      log.error( "Error with authenticator \"" . $authenticator . "\": " . $auth['Error'] );
 
      return "Authentication Error";
 
   } else if( !$auth['OK'] ) { #//Auth is not OK
 
      # Unauthorised
 
      log.warn("Access Denied - invalid username or password for user: \"" . $u . "\"" );
 
      return "Access Denied - invalid username or password";
 
   } else if ( $auth['OK'] ){
 
      log.info("Authenticated \"" . $u . "\" successfully at " . sys.localtime.format( "%a, %d %b %Y %T EST" ));
 
      if ( lang.isArray($auth['memberOf'])){ #//More than one group returned
 
         foreach ($group in $auth['memberOf']){
 
            if ($group == $g) {
 
               log.info("User \"" . $u . "\" permitted access at " . sys.localtime.format( "%a, %d %b %Y %T EST" ));
 
               return "PASS";
 
               break;
 
            } else {
 
               log.warn("User \"" . $u . "\" denied access - not a member of \"" . $g . "\" at " . sys.localtime.format( "%a, %d %b %Y %T EST" ));
 
            }
         }
 
         #// If we get to here, we have exhausted list of groups with no match
 
         return "FAIL";
 
 
      } else { #// This means that only one group is returned
 
         $group = $auth['memberOf'];
 
            if ($group == $g) {
 
               log.info("User \"" . $u . "\" permitted access " . sys.localtime.format( "%a, %d %b %Y %T EST" ));
 
               return "PASS";
 
               break;
 
            } else {
 
               log.warn("User \"" . $u . "\" denied access - not a member of \"" . $g . "\" at " . sys.localtime.format( "%a, %d %b %Y %T EST" ));
 
               return "FAIL";
 
            }
      }
   }
}
 
sub promptAuth401(){
 
   if (!http.getHeader("Authorization")) { #// no Authorization header present, lets challenge for credentials
 
      challengeBasicAuth("Error Message", "Realm");
 
   } else {
 
      $authHeader = http.getHeader( "Authorization" );
 
      $up = basicAuthExtractUserPass($authHeader);
 
 
      return $up;
   }
}
 
sub promptAuthHttpForm(){
 
   $response = "<html> <head>Authenticate me...</head> <form action=/login method=POST> <input name=user required> <input name=realm type=hidden value=stingray> <input name=pass type=password required> <button>Log In</button> </form> </html>";
 
   doHtmlResponse.200($response);
}

 

Contributors