CAS-NG

namibiancurrishInternet και Εφαρμογές Web

12 Νοε 2013 (πριν από 3 χρόνια και 8 μήνες)

69 εμφανίσεις

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)

Enhanced

CAS 3


Trust

Existing

Satisfied

Services

New Services

requiring

new function

Validate

Validate

Departmental Local Function

Existing

Central

CAS 3 (or 2)

Departmental

CAS 3


Trust

Department

Service

Validate

Departmental

CAS 3


Trust

Department

Service

Validate

Central

Service

Simple Peer Federation

CAS

Service

Service

Campus

CAS

client

trust

Other Institution

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

login WebFlow

/cas/login

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

Bin
Laden

front

end

CAS

Q: Who is this guy? A: “Bin Laden”

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 non
-
programmers to get it right


XACML is irrational


Institutional logic: Just what is a …

CASNG makes the decisions

Bin
Laden

Dumb Service

CAS

Client


with

script

uri

CAS

/cas/scriptedValidate,ticket=…,


service=…,acscript={uri}

script

data getter

data getter

data getter

data getter

HR

student

system

FBI

Alumni

CAS 3

Web (MVC)

View (JSP or

Redirect)

Controller

Validate

Login

WebFlow

Ticket CRUD

Business Logic

handler

handler

handler

resolver

resolver

resolver

Ticket

Cache

optional

store

Auth

Mgr

TrustedOtherCas

scripts

Background: Spring MVC

CAS

mod of

Spring

Servlet

HTTP

Web.xml

servlet

URL mappings

Bean

Bean

Bean

MVC

URL

mappings

Bean

Bean

Login

Web

flow

/login

/validate

Spring Side

Servlet Side

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

Spring

Servlet

URL to

bean map

Action Bean

Request

ModelAndView

Properties

file

JSP


(or View
Bean)

ViewName

varname

value

varname

value

varname

value

Model

EL

Plug it In

Spring

Servlet

URL to

bean map

Scripted

Validate

Controller

/scriptedValidate

ModelAndView

Properties

file

JSP


(or View
Bean)

ViewName

varname

value

varname

value

varname

value

Model

EL

Service

Validate

Controller

CAS Business Logic API

Ticket CRUD

Business Logic

handler

handler

handler

resolver

resolver

resolver

Ticket

Cache

optional

store

Auth

Mgr

If this was a real J2EE application, this would be the EJB layer

String createTicketGrantingTicket(Cred)

String grantServiceTicket(st, Service)

String grantServiceTicket(st, Service, Cred)

Assertion validateServiceTicket(st, Service)

void destroyTicketGrantingTicket(st)

String delegateTicketGrantingTicket(st, Cred)


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

handler

“I do”

resolver

resolver

resolver

“I do”

Ticket Cache




Auth Mgr

“who handles
this type of

Credential?”

WebFlow

Action Bean

returns

Credential

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

Yes

Issue ST

No

Gateway request

Yes

Redirect back

No

X.509 cert provided

Yes

Create TGT

No

Display the Form

Submit

Password Valid

No

Yes

Create TGT

Trusted Other Cas

/login

Is a cookie/TGT provided

Yes

Issue ST

No

Gateway request

Yes

Redirect back

No

X.509 cert provided

Yes

Create TGT

No

ticket= present (and validates to other CAS)

Yes

Create TGT

No

Redirect to Other CAS

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">



</view
-
state>


<end
-
state id="
otherCasRedirect
“ view="bean:
trustedOtherCas
" />


Note: now you never get here

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 cas
-
server
-
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)

Validate CAS2 ST

CAS2
Netid

becomes

CAS3 principal

Issue CAS3 TGT cookie

Issue CAS 3 ST

Validate

ticket= in

cookie and ticket=

back

Validate ST (with scripting)

Script

library

Rhino

JavaScript

Engine

Ticket

Cache

ScriptedValidateController

ServiceValidate

Controller

Is ST valid?

Is access permitted?

handleRequestInternal
()

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 init
-
param) 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 {


info =
engine.eval(scriptReader, bindings);

} 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.