FreeRadius 3.0.13 rlm_rest restful api authenticat

2020-07-30 04:20发布

问题:

I'm trying to authenticate Radius Requests against Restful API. My Virtual Server configuration as below:

authorize {
    filter_username
    filter_password
    preprocess
    auth_log

    if (User-Password) {
        update control {
            Auth-Type := rest
        }
    }
}

authenticate {
    rest
}

My radius -X output is:

(0) Received Access-Request Id 202 from 127.0.0.2:10708 to 127.0.0.2:1812 length 73
(0)   User-Name = "bob"
(0)   User-Password = "hello"
(0)   NAS-IP-Address = 127.0.0.2
(0)   NAS-Port = 1
(0)   Message-Authenticator = 0xcd622e98255234964d081be2513a0a9c
(0) # Executing section authorize from file /usr/local/etc/raddb/sites-enabled/testserver
(0)   authorize {
(0)     policy filter_username {
(0)       if (&User-Name) {
(0)       if (&User-Name)  -> TRUE
(0)       if (&User-Name)  {
(0)         if (&User-Name =~ / /) {
(0)         if (&User-Name =~ / /)  -> FALSE
(0)         if (&User-Name =~ /@[^@]*@/ ) {
(0)         if (&User-Name =~ /@[^@]*@/ )  -> FALSE
(0)         if (&User-Name =~ /\.\./ ) {
(0)         if (&User-Name =~ /\.\./ )  -> FALSE
(0)         if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))  {
(0)         if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))   -> FALSE
(0)         if (&User-Name =~ /\.$/)  {
(0)         if (&User-Name =~ /\.$/)   -> FALSE
(0)         if (&User-Name =~ /@\./)  {
(0)         if (&User-Name =~ /@\./)   -> FALSE
(0)       } # if (&User-Name)  = notfound
(0)     } # policy filter_username = notfound
(0)     policy filter_password {
(0)       if (&User-Password &&            (&User-Password != "%{string:User-Password}")) {
(0)       EXPAND %{string:User-Password}
(0)          --> hello
(0)       if (&User-Password &&            (&User-Password != "%{string:User-Password}"))  -> FALSE
(0)     } # policy filter_password = notfound
(0)     [preprocess] = ok
(0) auth_log: EXPAND /antikor/log/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/auth-detail-%Y%m%d
(0) auth_log:    --> /antikor/log/radacct/127.0.0.2/auth-detail-20170429
(0) auth_log: /antikor/log/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/auth-detail-%Y%m%d expands to /antikor/log/radacct/127.0.0.2/auth-detail-20170429
(0) auth_log: EXPAND %t
(0) auth_log:    --> Sat Apr 29 19:46:26 2017
(0)     [auth_log] = ok
(0)     if (User-Password) {
(0)     if (User-Password)  -> TRUE
(0)     if (User-Password)  {
(0)       update control {
(0)         Auth-Type := rest
(0)       } # update control = noop
(0)     } # if (User-Password)  = noop
(0)   } # authorize = ok
(0) Found Auth-Type = rest
(0) # Executing group from file /usr/local/etc/raddb/sites-enabled/testserver
(0)   authenticate {
rlm_rest (rest): Reserved connection (0)
(0) rest: Expanding URI components
(0) rest: EXPAND http://127.0.0.1:8902
(0) rest:    --> http://127.0.0.1:8902
(0) rest: EXPAND /test.php?action=authenticate
(0) rest:    --> /test.php?action=authenticate
(0) rest: Sending HTTP POST to "http://127.0.0.1:8902/test.php?action=authenticate"
(0) rest: EXPAND {"username":"%{User-Name}", "password":"%{User-Password}"}
(0) rest:    --> {"username":"bob", "password":"hello"}
(0) rest: Processing response header
(0) rest:   Status : 200 (OK)
(0) rest:   Type   : json (application/json)
(0) rest: Parsing attribute "control:Cleartext-Password"
(0) rest: EXPAND hello
(0) rest:    --> hello
(0) rest: Cleartext-Password := "hello"
(0) rest: Parsing attribute "request:User-Password"
(0) rest: EXPAND hello
(0) rest:    --> hello
(0) rest: User-Password := "hello"
(0) rest: Parsing attribute "reply:Reply-Message"
(0) rest: EXPAND Hello bob
(0) rest:    --> Hello bob
(0) rest: Reply-Message := "Hello bob"
rlm_rest (rest): Released connection (0)
Need 5 more connections to reach 10 spares
rlm_rest (rest): Opening additional connection (5), 1 of 27 pending slots used
rlm_rest (rest): Connecting to "http://127.0.0.1:8902/test.php"
(0)     [rest] = updated
(0)   } # authenticate = updated
(0) Failed to authenticate the user
(0) Login incorrect: [bob/hello] (from client antikor-l2tp port 1)
(0) Using Post-Auth-Type Reject
(0) # Executing group from file /usr/local/etc/raddb/sites-enabled/testserver
(0)   Post-Auth-Type REJECT {
(0) attr_filter.access_reject: EXPAND %{User-Name}
(0) attr_filter.access_reject:    --> bob
(0) attr_filter.access_reject: Matched entry DEFAULT at line 11
(0)     [attr_filter.access_reject] = updated
(0)     [eap] = noop
(0)     policy remove_reply_message_if_eap {
(0)       if (&reply:EAP-Message && &reply:Reply-Message) {
(0)       if (&reply:EAP-Message && &reply:Reply-Message)  -> FALSE
(0)       else {
(0)         [noop] = noop
(0)       } # else = noop
(0)     } # policy remove_reply_message_if_eap = noop
(0)   } # Post-Auth-Type REJECT = updated
(0) Delaying response for 1.000000 seconds
Waking up in 0.3 seconds.
Waking up in 0.6 seconds.
(0) Sending delayed response
(0) Sent Access-Reject Id 202 from 127.0.0.2:1812 to 127.0.0.2:10708 length 33
(0)   Reply-Message = "Hello bob"

I added both control:Cleartext-Password and request:User-Password variables to test.php json reply. tried one by one. But still authentication step fails. JSON output is as below:

{"control:Cleartext-Password":"hello", "request:User-Password":"hello","reply:Reply-Message":"Hello bob"}

I wonder that if the JSON response is wrong and how should it be for Authentication reply?

Thanks.

回答1:

The authorize method rlm_rest module acts like other datastore modules like rlm_sql, rlm_redis and rlm_couchbase.

It is mainly for retrieving AVPs from a remote source, it can be used as an authentication module, but not in the way you were calling it above (example at the bottom of this answer).

With the way you're calling rlm_rest, In order for the user to be accepted, you'll need to list another module that can look at the attributes in the request, look at what you got back from your rest API, and figure out what type of authentication to perform. If you're doing plaintext authentication (i.e. no EAP) then you can use the pap module.

Your server config would then look something like

authorize {
    rest
    pap
}

authenticate {
    pap
}
  • rest.authorize retrieves control:Cleartext-Password which gives the server the "good" password to compare against the password the user sent.

  • pap.authorize checks to see if request:User-Password exists, and if it does, sets control:Auth-Type pap.

  • pap.authenticate compares control:Cleartext-Password with request:User-Password and if they match returns ok or reject depending on whether they do or not.

The other way of authenticating a plaintext userr in this case is by using HTTP BasicAuth and rlm_rest's authenticate method. The policy for that would look something like this:

authorize {
    if (&User-Password) {
        update control {
            Auth-Type := 'rest'
        }
    }
}

authenticate {
    rest
}