Technical Forum
Ask questions. Discover Answers.
cancel
Showing results for 
Search instead for 
Did you mean: 

Help with IRule Client Auth Certs

Mr_Moody
Nimbostratus
Nimbostratus

I have an IRule below that I'm working on. My intent is to enforce client certificate authentication on two URI's only and if any client certificate errors should result in a redirect to a custom error page. The VS has a SSL profile set to 'ignore' client certificates. This rule successfully processes the first two 'If' statements. The problem is that the custom error page is not displayed. Any help would be appreciated.

when HTTP_REQUEST {
	if { not ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
			return
	} else {

if { ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
		SSL::session invalidate
    SSL::authenticate always
    SSL::authenticate depth 9
    SSL::cert mode require
    set cmd "SSL::profile /Common/require_clientssl"
    eval $cmd
    SSL::renegotiate
 	} else {
if {[SSL::verify_result] == 0 }{
			return			
  } else {
HTTP::respond 302 Location "http://error.com/error.html" Cache-Control No-Cache Pragma No-Cache
}
}
}
}

I have another rule that meets two of the three requirements. With the VS SSL profile set to 'request' client certs. This rule does provide a custom error page when Cert errors occur on the two named URI's. But it also results in a certificate prompt for users who access other URI's due to the default SSL profile setting.

when HTTP_REQUEST {
if { not ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
			return
	} else {
if {[SSL::verify_result] == 0 }{
			return			
  } else {
HTTP::respond 302 Location "http://error.com/error.html" Cache-Control No-Cache Pragma No-Cache
}
}
}

1 ACCEPTED SOLUTION

Simon_Blakely
F5 Employee
F5 Employee

Your HTTP::respond 302 is in the else clause of your second if statement.

It is never reached.

when HTTP_REQUEST {
	if { not ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
                        # This path has no client-authentication
			return
	} else {
      # perform client-authentication if the uri matches
      if { ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
		SSL::session invalidate
        SSL::authenticate always
        SSL::authenticate depth 9
        SSL::cert mode require
        set cmd "SSL::profile /Common/require_clientssl"
        eval $cmd
        SSL::renegotiate
 	  } else {
        # we cannot execute this path because of the first *if* statement
        if {[SSL::verify_result] == 0 }{
			return			
        } else {
          HTTP::respond 302 Location "http://error.com/error.html" Cache-Control No-Cache Pragma No-Cache
        }
      }
    }
}

Try something like

when HTTP_REQUEST {
	if { not ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
      # we don't need to renegotiate with client-authentication
	  return
	} else {
      # we do need to renegotiate with client-authentication
  	  SSL::session invalidate
      SSL::authenticate always
      SSL::authenticate depth 9
      SSL::cert mode require
      set cmd "SSL::profile /Common/require_clientssl"
      eval $cmd
      SSL::renegotiate
      # check if renegotiation with client-auth succeeded
      if {[SSL::verify_result] == 0 }{
		return			
      } else {
        HTTP::respond 302 Location "http://error.com/error.html" Cache-Control No-Cache Pragma No-Cache
      }
	}
}

but I haven't tested this to check ...

View solution in original post

2 REPLIES 2

Simon_Blakely
F5 Employee
F5 Employee

Your HTTP::respond 302 is in the else clause of your second if statement.

It is never reached.

when HTTP_REQUEST {
	if { not ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
                        # This path has no client-authentication
			return
	} else {
      # perform client-authentication if the uri matches
      if { ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
		SSL::session invalidate
        SSL::authenticate always
        SSL::authenticate depth 9
        SSL::cert mode require
        set cmd "SSL::profile /Common/require_clientssl"
        eval $cmd
        SSL::renegotiate
 	  } else {
        # we cannot execute this path because of the first *if* statement
        if {[SSL::verify_result] == 0 }{
			return			
        } else {
          HTTP::respond 302 Location "http://error.com/error.html" Cache-Control No-Cache Pragma No-Cache
        }
      }
    }
}

Try something like

when HTTP_REQUEST {
	if { not ([HTTP::uri] starts_with "/uri1") || ([HTTP::uri] starts_with "/uri2")} {
      # we don't need to renegotiate with client-authentication
	  return
	} else {
      # we do need to renegotiate with client-authentication
  	  SSL::session invalidate
      SSL::authenticate always
      SSL::authenticate depth 9
      SSL::cert mode require
      set cmd "SSL::profile /Common/require_clientssl"
      eval $cmd
      SSL::renegotiate
      # check if renegotiation with client-auth succeeded
      if {[SSL::verify_result] == 0 }{
		return			
      } else {
        HTTP::respond 302 Location "http://error.com/error.html" Cache-Control No-Cache Pragma No-Cache
      }
	}
}

but I haven't tested this to check ...

Thank you that was it! I also had to change the cert mode to 'request'.