CAS-NG A small enhancement to CAS 3 to provide new services Objectives [of this talk] • TrustedOtherCas – single sign-on to more than one.

Download Report

Transcript CAS-NG A small enhancement to CAS 3 to provide new services Objectives [of this talk] • TrustedOtherCas – single sign-on to more than one.

CAS-NG
A small enhancement to CAS 3
to provide new services
Objectives [of this talk]
• TrustedOtherCas – single sign-on to more than
one instance of the CAS codebase
• ScriptedValidate – Extend CAS ServiceValidate
with Access Control rules written in simple
scripting languages
• CAS Extensibility – How and where these
extensions fit into the architecture
Enable Additional CAS Function Now
Existing
Central
CAS 3 (or 2)
Validate
Existing
Satisfied
Services
Enhanced
CAS 3
Trust
Validate
New Services
requiring
new function
Departmental Local Function
Department
Service
Existing
Central
CAS 3 (or 2)
Central
Service
Departmental Validate
CAS 3
Trust
Departmental
CAS 3
Trust
Validate
Department
Service
Simple Peer Federation
Other Institution
Campus
CAS
trust
CAS
Service
client
Service
cas-server-support-trusted
existing CAS 3 optional subproject
J2EE Container
Web
Listener
Container
Based
Authentication
S
E
R
V
L
E
T
api
CAS
request.getRemoteUser()
trustedOtherCas – a WebFlow bean
that generates “trusted” credentials
CAS
/cas/login
login WebFlow
cookie
x.509 cert
other stuff
Form or
OtherCAS
CAS Filter logic turned into
a Web Flow Bean
TrustedOtherCas Step by Step
Get it in the WAR
• Get “cas-server-support-trusted-otherCAS”
project, put it in CAS 3 source directory
• Add name to top level POM module list [so it
gets compiled by Maven into a JAR]
• Add the “cas-server-support-trusted” and
“trusted-otherCAS” artifact JARs to the
webapp project POM dependency list [so JAR
gets added to the WAR WEB-INF/lib]
TrustedOtherCas Step by Step
Spring Configuration
• Add “trusted” project beans to the Handler
and Resolver bean list [so credentials can be
processed] in deployerConfigContext.xml
• In cas-servlet.xml, configure an instance of the
trustedOtherCas bean with the login and
validation URL of the other CAS
• Add OtherCas bean to login-webflow.xml and
change flow logic to go to it
There can be more than one
• If you have more than one trustedOtherCas,
each can have its own configured bean, but
• Each needs its own /loginXXX URL and its own
WebFlow because the ticket= doesn’t tell you
which CAS it came from, so you have to know
this based on the URL that CAS redirected
back to
Current CAS doesn’t do Access Control
Service created by Humanities Professor
CAS
Q: Who is this guy? A: “Bin Laden”
Bin
Laden
front
end
Should I let Bin Laden in?
All the institutional data about people is
over there somewhere, but ordinary users
don’t have access to it.
Allow access to licensed MP3 files to
•
•
•
•
Music department faculty
Music graduate students
Undergraduate Music majors
Students enrolled in “Music 202”
Beyond the programming skills of a Music prof
Access Control Problems
• Don’t want to give out access to HR, student
systems, and other institutional data to
everyone who has a Web application
• Access control is too complicated for nonprogrammers to get it right
• XACML is irrational
• Institutional logic: Just what is a …
CASNG makes the decisions
CAS
script
HR
student
system
data getter
data getter
FBI
data getter
Alumni
data getter
/cas/scriptedValidate,ticket=…,
service=…,acscript={uri}
Bin
Laden
CAS
Client
with
script
uri
Dumb Service
CAS 3
Web (MVC)
Ticket CRUD
Business Logic
View (JSP or
Redirect)
Controller
Auth
Mgr
Validate
handler
handler
handler
resolver
resolver
resolver
Ticket
Cache
Login
WebFlow
TrustedOtherCas
scripts
optional
store
Background: Spring MVC
Servlet Side
Spring Side
/validate
HTTP
CAS
mod of
Spring
Servlet
Web.xml
servlet
URL mappings
Bean
Bean
MVC
URL
Bean
mappings
/login
Login
Web
flow
Bean
Bean
WEB-INF/web.xml URL mapping
• <servlet><servlet-name>cas</servlet-name>
<servlet-class>
org.jasig.cas.web.init.SafeDispatcherServlet
• <servlet-mapping>
<servlet-name>cas</servlet-name>
<url-pattern>/scriptedValidate</url-pattern>
</servlet-mapping>
cas-servlet.xml then maps each
URL to a Spring Bean
<bean id="handlerMappingC"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/serviceValidate“>serviceValidateController</prop>
<prop key="/scriptedValidate“>scriptedValidateController</prop>
<prop key="/validate“>legacyValidateController</prop>
…
<bean id="serviceValidateController"
class="org.jasig.cas.web.ServiceValidateController"
p:validationSpecificationClass="org.jasig.cas.validation.Cas20WithoutProxying…"
p:centralAuthenticationService-ref="centralAuthenticationService"
p:proxyHandler-ref="proxy20Handler"
p:argumentExtractor-ref="casArgumentExtractor" />
Spring MVC request lifecycle
JSP
ModelAndView
EL
(or View
Bean)
Properties
file
ViewName
Model
varname
value
varname
value
varname
value
Action Bean
Spring
Servlet
URL to
bean map
Request
Plug it In
JSP
ModelAndView
EL
(or View
Bean)
Properties
file
Spring
Servlet
URL to
bean map
/scriptedValidate
ViewName
Model
varname
value
varname
value
varname
value
Scripted
Validate
Controller
Service
Validate
Controller
CAS Business Logic API
Ticket CRUD
Business Logic
String createTicketGrantingTicket(Cred)
String grantServiceTicket(st, Service)
String grantServiceTicket(st, Service, Cred)
Assertion validateServiceTicket(st, Service)
void destroyTicketGrantingTicket(st)
String delegateTicketGrantingTicket(st, Cred)
Auth
Mgr
handler
handler
handler
resolver
resolver
resolver
Ticket
Cache
optional
store
If this was a real J2EE application, this would be the EJB layer
Credentials
• Credentials is a marker interface (no methods)
added to any class that may authenticate a
user (X.509 Cert, Password, …)
• A Handler validates the credentials (“The Cert
was issued by a trusted CA”)
• A Resolver maps the Credential to a netid (by
extracting the Netid from, say, the first CN in
the Cert DN)
CAS API
Ticket CRUD
Business Logic
handler
handler
WebFlow
Action Bean
returns
Credential
Auth Mgr
“who handles
this type of
Credential?”
handler
“I do”
resolver
resolver
resolver
“I do”
Ticket Cache
Principal
Spring WebFlow
• URL mapped to WebFlow [new XML]
• Set Initial state
• ActionState runs a bean or makes a EL test.
Success/Failure chooses new state
• ViewStates display a Form, input goes to an
Action Bean
• An EndState releases Flow scoped objects
• Use for a single page is unexpected
Login Webflow
/login
Is a cookie/TGT provided
No
Yes
Issue ST
Gateway request
No
Yes
X.509 cert provided
No
Yes
Redirect back
Create TGT
Display the Form
Submit
No
Password Valid
Yes
Create TGT
Trusted Other Cas
/login
Is a cookie/TGT provided
No
Yes
Issue ST
Gateway request
No
Yes
X.509 cert provided
No
Yes
ticket= present (and validates to other CAS)
No
Yes
Redirect to Other CAS
Redirect back
Create TGT
Create TGT
Add to WEB-INF/cas-servlet.xml
<bean id="trustedOtherCas"
class=“…trusted.web.flow.PrincipalFromOtherCasNonInteractiveCredentialsAction"
p:centralAuthenticationService-ref="centralAuthenticationService"
p:loginUrl = "https://secure.its.yale.edu/cas/login"
p:validateUrl = https://secure.its.yale.edu/cas/proxyValidate
/>
WEB-INF/login-webflow.xml
<action-state id="startAuthenticate">
<action bean="x509Check" />
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="error" to="tryOtherCas" />
</action-state>
<action-state id="tryOtherCas">
<action bean="trustedOtherCas" />
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="error" to="otherCasRedirect" />
</action-state>
<view-state id="viewLoginForm" view="casLoginView">
Note: now you never get here
…
</view-state>
<end-state id="otherCasRedirect“ view="bean:trustedOtherCas" />
CAS WebFlow Bean
public final class
PrincipalFromOtherCasNonInteractiveCredentialsAction
extends AbstractNonInteractiveCredentialsAction
implements ViewSelector {
…
protected Credentials
constructCredentialsFromRequest(
…
return new PrincipalBearingCredentials(
new SimplePrincipal(remoteUser));
CAS internal API mapped to
WebFlow concepts
• Return null follows “failure” state change
(View method redirects to other CAS)
• Return Credentials follows “success” state
change (to Create TGT)
• deployerConfigContext.xml must have casserver-support-trusted Handler and Resolver
that process this type of Credentials
There can be more than one
• If you have more than one trustedOtherCas,
each can have its own configured bean, but
• Each needs its own /loginXXX URL and its own
WebFlow because the ticket= doesn’t tell you
which CAS it came from, so you have to know
this based on the URL that CAS redirected
back to
WEB-INF/deployerConfigContext.xml
<bean id="authenticationManager"
class="org.jasig.cas.authentication.AuthenticationManagerImpl">
<property name="credentialsToPrincipalResolvers">
<list>
<bean class=“…principal.UsernamePasswordCredentialsToPrincipalResolver" />
<bean class=“…trusted...PrincipalBearingCredentialsToPrincipalResolver" />
<bean class=“…x509...X509CertificateCredentialsToIdentifierPrincipalResolver"
p:identifier="$CN" />
<property name="authenticationHandlers">
<list>
<bean class=“…trusted...PrincipalBearingCredentialsAuthenticationHandler" />
<bean class=“…x509…X509CredentialsAuthenticationHandler“
<bean class=“…JaasAuthenticationHandler" />
cas-server-webapp/pom.xml
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-support-trusted</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-support-trusted-otherCAS</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-scripting</artifactId>
<version>${project.version}</version>
</dependency>
Browser Comes to CAS 3
Test
Existing Cookie
X509
Windows login
Redirect to CAS 2
Redirect to Other CAS (CAS 2)
display Form
Validate password
Issue TGT cookie
Issue ST for CAS3
Redirect back to CAS 3
(as Other CAS Service)
ticket= in
cookie and ticket=
back
Validate
Validate CAS2 ST
CAS2 Netid becomes
CAS3 principal
Issue CAS3 TGT cookie
Issue CAS 3 ST
Validate ST (with scripting)
ServiceValidate
Controller
ScriptedValidateController
Ticket
Cache
Is ST valid?
handleRequestInternal()
Is access permitted?
Rhino
JavaScript
Engine
Script
library
Several ways to intercept the
call to a single method
• Subclassing [requires removing “final” from
parent class]
• Delegation: Create a separate
ServiceValidateController bean instance
• AOP: Intercept the handleRequestInternal call,
add script “advice” to the return
Success and Failure ViewName
properties
• Subclass: one object (inherit the field)
• Delegate: ScriptedValidate is configured, then
it sets the property value in the captive
ServiceValidate object
• AOP: ???
cas-servlet.xml
<prop key="/scriptedValidate“>scriptedValidateController</prop>
<bean id="scriptedValidateController"
class="org.jasig.cas.web.ScriptedValidateController“
[properties inherited from superclass ServiceValidateController] >
<property name="builders">
… List of beans that add variables to the JS environment
<property name="scripts">
.. . list of inline scripts keyed by URI
<property name="scriptResources">
… resource url of script files (file:. classpath:, http:, …)
There can be more than one
• You can have multiple /scriptedValidate URLs,
with more than one Bean, with more than one
configuration
• One for scripts with public data
• One for more carefully controlled scripts with
access to more sensitive data
• …
/scriptedValidate,acscript=“…uri…”,…
• Service (through the configured Filter initparam) designates a script by URI
• Spring XML configuration passes a Map to the
bean. The keys are URIs. The values are
– The inline text of the script
– A file (local path, in WAR, http: URL)
– A directory (if the URI key ends in “:*”)
The Directory Rule
• The CAS XML Map associates “cas:stuff:*”
with /usr/local/casscripts/
• The Service sets acscript=cas:stuff:foo.js
• CAS runs /usr/local/casscripts/foo.js
Java 6 JS (Rhino)
• Bindings contains a Map<String,Object>
• Key becomes a JS variable name
• Java object becomes a JS object (script can
reference properties, call methods)
• Rhino adds built in packages. and java.
variables so script can use native Java objects,
but we want to prevent access to local files
and stuff.
Built-In JS Variables
• “java” and “packages” override
• “netid” is Principal ID
• “request” provided limited access to some
HttpServletRequest info (parameters)
• “log” is log4j as in log.info(msg)
ObjectBuilder
public interface ObjectBuilder {
public abstract Map<String, Object> buildObjects(String netid);
LDAP Object Builder
<!-- Apache LDAP Directory Server running on localhost -->
<bean id="localLdapDao" class="edu.yale.its.tp.cas.scripting.LdapDao"
p:ldapUrl="ldap://localhost:10389/dc=example,dc=com"
p:ldapPassword = "yalescout"
p:ldapUserid = "uid=yalescout,ou=users,ou=system"
p:testLookup = "ou=system"
p:netidAttribute = "uid"
/>
<bean id="localLdap" class="edu.yale.its.tp.cas.scripting.LdapUserObjectBuilder"
p:dao-ref="localLdapDao" p:variableName="mydir"
/>
JDBC Object Builder
<bean id="employeeTable"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
<property name="url" value="jdbc:derby://localhost:1527/myeclipse" />
<property name="username" value="app" />
<property name="password" value="dummy" />
</bean>
<bean id="jdbcUserBuilder" class="edu.yale.its.tp.cas.scripting.JdbcUserObjectBuilder"
p:datasource-ref="employeeTable"
p:query="select * from app.employee where netid=?"
p:variableName="dbuser"
/>
ScriptedValidateController property
<property name="builders">
<list>
<ref bean="localLdap" />
<ref bean="jdbcUserBuilder" />
</list>
</property>
ScriptedValidateController
[run the script]
Object info = null;
try {
engine.eval(scriptReader, bindings);
info =
} catch (Exception e) {
log.error("Error in the access control script: " + e);
failClient("ScriptError","The access control script ended in error.", result);
return result;
}
if (info instanceof String) {
Script Result
• The result of the script is the value of the last
expression as in
“drop dead”; or 666;
• Access permitted by “” or 0
• Access refused if non-empty string or non zero
number, but
• Nothing from the script is sent back to the
service, just the OK or rejection.
Prereqs
• Modified version of CAS 3 client
– Generates the acscript= parameter
– processes “ScriptReject” validation failure
response and turns it into a 403 Forbidden status.
Client
<filter>
<filter-name>CASValidateFilter</filter-name>
<filter-class>org.jasig.cas.client.validation.
Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://cas.example.com:8443/cas</param-value>
</init-param><init-param>
<param-name>serverName</param-name>
<param-value>http://cas.example.com:8080</param-value>
</init-param><init-param>
<param-name>scriptUri</param-name>
<param-value>cas:some:name</param-value>
</init-param><init-param>
<param-name>scriptParams</param-name>
<param-value>group list or something</param-value>
</init-param>
</filter>
“Research”
• Add prepackaged script URIs
acscript=cas:isInAdGroup, acparam=wizards
• Remote debug error messages for a script
developer
• Mostly, how to turn this from a working
testbed into a finished product.