security in enterprise java
DESCRIPTION
Speaker: Arne Limburg W-JAX 2012 Security ist nach wie vor das Sorgenkind in Java EE. Das rollenbasierte Access-Control-Konzept hat sich in der Praxis als unzureichend erwiesen. Das Thema Cloud Computing stellt zudem weitere Anforderungen an die Security. In der Session wird vorgestellt, was der Java-EE-Standard in diesem Bereich bisher bietet, was in Java EE 7 kommen wird und welche Alternativen es gibt, wenn der Standard nicht ausreicht.TRANSCRIPT
Arne Limburg // open knowledge GmbH
Aber sicher!Security in Enterprise Java
Meine Person
Open Source• JPA Security• Apache DeltaSpike• Apache OpenWebBeans
Arne LimburgEnterprise Architectopen knowledge GmbH
@ArneLimburg@_openknowledge
www.openknowledge.de
Schwerpunkte• JPA• CDI
Enterprise Application Security
Authentication
Authorization Network Security- OS- Firewall - TCP/IP
Webserver- Konfiguration
Kommunikationssicherheit- HTTP / HTTPS- Application-Firewall
BeispielanwendungE-Learning Plattform
Security-Anforderungen
• Nur Dozenten dürfen Kurse anlegen• Dozenten dürfen Veranstaltungen für
ihre Kurse anlegen• Dozenten dürfen nur Studenten sehen,
die an ihren Kursen teilnehmen• Studenten dürfen nur Mitstudenten
sehen, mit denen sie gemeinsame Kurse haben
Authentication vs. Authorization
Wer ist der aktuelle Benutzer?
Authentication
Nutzername / Kennwort
Public Key
OAuth
Biometrisch
Authentication in einer Web-App.web.xml
<login-config> <auth-method>FORM</auth-method> <realm-name>JAAS</realm-name> <form-login-config> <form-login-page>/login.xhtml</…> <form-error-page>/error.xhtml</…> </form-login-config> </login-config>
Servlet 3.0 Authentication
public void login(HttpServletRequest request, String username, String password) { request.login(username, password);}
public void logout(HttpServletRequest req) { req.logout();}
Was darf der aktuelle Benutzer?
Authorization
Rollenbasiert
User-Permissions
Access Control Lists
Domain-Object-Security
Was darf der aktuelle Benutzer?
Authorization
Rollenbasiert
User-Permissions
Access Control Lists
Domain-Object-Security
JAAS
• Pluggable Authentication• Authorization
– Pluggable Policy-Provider– Permission-Checks über AccessController
Java PermissionsPolicy-Datei
grant principal de…User "arne" { de…ExecPermission "de…CourseDao.find*"}
grant principal de…User "admin" { de…ExecPermission "de…CourseDao.*"}
Java Permissions
public class ExecPermission extends BasicPermission {
public ExecPermission(String methodName) { super(methodName); }}
Java Permissionspublic void create(Course course) {
String methodName = "de…CourseDao.create";
AccessController.checkPermission( new ExecPermission(methodName); );
entityManager.persist(course);}
Fazit Permissons
• Jede Security-Anforderung abbildbar• Aber
– Viel zu aufwendig– Schlecht wartbar
Erweiterungen nötig
Was darf der aktuelle Benutzer?
Authorization
Rollenbasiert
User-Permissions
Access Control Lists
Domain-Object-Security
Was darf der aktuelle Benutzer?
Authorization
Rollenbasiert
User-Permissions
Access Control Lists
Domain-Object-Security
Role based Access Control
Create Course
Read Course
…
Permissions
Read Student
Teacher
Student
RolesUsers
Teacher 1
Student 1
…
Student 2
Role based Access Control
Servlet SpecPermissions für Web-Resources
Role based Access Controlweb.xml
<security-constraint> <web-resource-name>New Course</…> <url-pattern>/courses/create.xhtml</…> <auth-constraint> <role-name>teacher</…> </auth-constraint> </security-constraint>
Role based Access Control
Servlet SpecPermissions für Web-Resources
Java EE SecurityPermissions für Klassen und Methoden
Role based Access Control in Java EE
@DeclareRoles
@RolesAllowed@PermitAll@DenyAll
JACC
Java Authorization Contract for Containers• Implementierung ist verantwortlich für:
– Rollen als Sammlung von Permissions– Granting von Permissions– Überprüfung von Permissions
Role Based Access Control
@RolesAllowed("teacher")public Course create(Teacher lecturer, …) { Course course = new Course(lecturer, …); entityManager.persist(course); return course;}
@RolesAllowed("teacher")public Course create(Teacher lecturer, …) { Course course = new Course(lecturer, …); entityManager.persist(course); return course;}
Anforderung:Dozenten dürfen nur ihre Kurse anlegen.
Anforderung:Dozenten dürfen nur ihre Kurse anlegen.
Role Based Access Control
Role Based Access Control@Resourceprivate EjbContext context;
public Course create(Teacher lecturer, …) { Principal caller = ejbContext.getCallerPrincipal(); if (!lecturer.equals(caller)) { throw new SecurityException(…); } …}
Role Based Access Control@Resourceprivate EjbContext context;
public Course create(Teacher lecturer, …) { Principal caller = ejbContext.getCallerPrincipal(); if (!lecturer.equals(caller)) { throw new SecurityException(…); } …}
Das Rollenkonzept ist sehr limitiert!
Komplexere Access-Control-Anforderungen finden sich im Code „verstreut“ wieder!
Wartbarkeits- und Erweiterbarkeitsprobleme!
Alternativen zu Role based Access Control?
Alternativen zu Role based Access Control?
Die Rechte sollten nicht danach vergeben werden, was der Benutzer ist
(welche Rolle er hat),sondern danach, was er darf!
<h:outputLink value="editCourse.xhtml" rendered ="#{sec:isUserInRole('teacher')}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Edit Course"/>
</h:outputLink>
Beispiel I
Beispiel I<h:outputLink value="editCourse.xhtml" rendered ="#{sec:isUserInRole('teacher')}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Edit Course"/>
</h:outputLink>
Beispiel I<h:outputLink value="editCourse.xhtml" rendered ="#{sec:hasPermission('editCourse')}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Edit Course"/>
</h:outputLink>
Beispiel I<h:outputLink value="editCourse.xhtml" rendered ="#{sec:canUpdate(course)}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Edit Course"/>
</h:outputLink>
<h:outputLink value="createLesson.xhtml" rendered ="#{sec:isUserInRole('teacher')}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Create Lesson"/>
</h:outputLink>
Beispiel II
<h:outputLink value="createLesson.xhtml" rendered ="#{sec:isUserInRole('teacher')}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Create Lesson"/>
</h:outputLink>
Beispiel II
<h:outputLink value="createLesson.xhtml" rendered ="#{sec:hasPermission('createLesson')}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Create Lesson"/>
</h:outputLink>
Beispiel II
<h:outputLink value="createLesson.xhtml" rendered ="#{sec:canCreate('Lesson', course)}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Create Lesson"/>
</h:outputLink>
Beispiel II
Was darf der aktuelle Benutzer?
Authorization
Rollenbasiert
User-Permissions
Access Control Lists
Domain-Object-Security
Was darf der aktuelle Benutzer?
Authorization
Rollenbasiert
User-Permissions
Access Control Lists
Domain-Object-Security
Access Control Lists
Object Access Control List
Access Control Entry
Access Control Entry
Access Control Entry
User 1
User 2
User 3
Spring Security
Security für spring-basierten Web-Apps• Umfangreiche Authentication-Module• Authorization
– Request-basiert– Methoden-basiert– Access Control Lists
ACLs in Spring Security
public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
ACLs in Spring Security
public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
Anforderungen:Dozenten dürfen nur Studenten sehen, die ihre
Kurse besuchen.
Studenten dürfen nur Kommilitonen sehen, mit denen sie gemeinsame Kurse haben.
ACLs in Spring Security
Spring Context
<global-method-security pre-post-annotations="enabled" />
ACLs in Spring Security
@PostFilter ("hasPermission(filterObject, 'read')")public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
ACLs in Spring Security
@PostFilter ("hasPermission(filterObject, 'read')")public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
Problem:
Filtern passiert im Speicher!
Schlechte Performance bei großen Datenmengen!
ACLs in Spring Security
@PostFilter ("hasPermission(filterObject, 'read')")public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
Anforderung:Dozenten dürfen nur ihre Kurse anlegen.
ACLs in Spring Security@PreAuthorize ("hasPermission(#course, 'create')")public void create(Course course) { entityManager.persist(course);}
AccessDeniedException
ACLs in Spring Security@PreAuthorize ("hasPermission(#course, 'create')")public void create(Course course) { entityManager.persist(course);}
AccessDeniedException
Weiteres Problem:
Wie kommen die ACLs in die Datenbank?
ACLs in Spring Security@PreAuthorize ("hasPermission(#course, 'create')")public void create(Course course) { entityManager.persist(course);}
ACLs in Spring Security@PostAuthorize ("hasPermission(returnedObject, 'create')")public Course create(Course course) { entityManager.persist(course); return course;}
ACLs in Spring Security@PostAuthorize ("hasPermission(returnedObject, 'create')")public Course create(Course course) { entityManager.persist(course); ObjectIdentity identity = new ObjectIdentityImpl(Course.class, course.getId()); …}
ACLs in Spring Security@PostAuthorize ("hasPermission(returnedObject, 'create')")public Course create(Course course) { entityManager.persist(course); ObjectIdentity identity = …; String name = course.getTeacher().getName(); PrincipalSid principal = new PrincipalSid(name);
ACLs in Spring Security@PostAuthorize ("hasPermission(returnedObject, 'create')")public Course create(Course course) { entityManager.persist(course); ObjectIdentity identity = …; PrincipalSid principal = …; MutableAcl acl = aclService.createAcl(i); acl.insertAce(0, CREATE, principal, true); aclService.updateAcl(acl); return course;}
ACLs in Spring Securitypublic void add(Course course, Student student) { course.subscribe(student); createACE(student, course.getLecturer()); for (Student participant: course.getParticipants()) { createACE(student, participant); createACE(participant, student); }}
ACLs in Spring Securitypublic void add(Course course, Student student) { course.subscribe(student); createACE(student, course.getLecturer()); for (Student participant: course.getParticipants()) { createACE(student, participant); createACE(participant, student); }}
Anlegen und Löschen von ACLs findet sich im Code „verstreut“ wieder!
Wartbarkeits- und Erweiterbarkeitsprobleme!
Was passiert, wenn ein Entwickler vergisst, eine ACL anzulegen oder zu löschen?
Authorization
Rollenbasiert
User-Permissions
Access Control Lists
Domain-Object-Security
Was darf der aktuelle Benutzer?
Authorization
Rollenbasiert
User-PermissionsDomain-Object-Security
Access Control Lists
Was darf der aktuelle Benutzer?
DeltaSpike Security
• Authentication– Yet to come…
• Authorization– Business-Method via Annotations
DeltaSpike Security
@Createpublic Course create( @Owner Teacher lecturer, …) { Course course = new Course(lecturer, …); entityManager.persist(course); return course;}
Eigene Security-Annotation
@SecurityBindingTypepublic @interface Create {}
@SecurityParameterBindingpublic @interface Owner {}
Separate Logik-Implementierung
public class SecurityRules { @Secures @Create public boolean checkOwner(@Owner User owner, Identity user) { return owner.equals(user); }}
DeltaSpike Security
@Createpublic Course create( @Owner Teacher lecturer, …) { Course course = new Course(lecturer, …); entityManager.persist(course); return course;}
DeltaSpike Security
@Createpublic Course create( @Owner Teacher lecturer, …) { Course course = new Course(lecturer, …); entityManager.persist(course); return course;}
Check des Rückgabe-Wertes noch nicht so elegant möglich!
DeltaSpike Security
Check des Rückgabe-Wertes• Implementieren einer @Alternative SecurityStrategy
• Interface an Interceptor-API angelehnt
DeltaSpike Security@Alternativepublic class MySecurityStrategy implements SecurityStrategy {
public Object execute (InvocationContext ctx) { result = ctx.proceed(); // check result here return result; }}
DeltaSpike Security@Alternativepublic class MySecurityStrategy extends DefaultSecurityStrategy {
public Object execute (InvocationContext ctx) { result = super.execute(ctx); // check result here return result; }}
Spring Security
@PreAuthorize("#lecturer == principal")@PostAuthorize ("returnedObject.lecturer == principal")public Course create(Teacher lecturer, …) { Course course = new Course(lecturer, …); entityManager.persist(course); return course;}
Domain-Object-basiert
@PreAuthorize("#lecturer == principal")@PostAuthorize ("returnedObject.lecturer == principal")public Course create(Teacher lecturer, …) { Course course = new Course(lecturer, …); entityManager.persist(course); return course;}
Was ist, wenn das Anlegen des Kurses nicht über die create-Methode erfolgt?
Seam Security
• Authentication– JAAS (Seam 2)– PicketLink (Seam 3)
• Authorization– JSF– Business-Method– Entity (nur Seam 2)
Seam 2 Security
Rule-based Authorization mit Drools
Auch auf Entitäten-Ebene
Entity-Security in Seam 2
@Restrict@Entitypublic Course { …}
Entity-Security in Seam 2
Drools Konfiguration rule CreateCourse no-loop activation-group "permission"when principal: Principal() course: Course(lecturer: lecturer -> (lecturer.equals(principal))) check: PermissionCheck(target == course, action == "insert", granted == false)then check.grant();end;
Entity-Security mit Seam 2orm.xml
<persistence-unit-metadata> <persistence-unit-defaults> <entity-listeners> <entity-listener class= "org.jboss.seam.security.EntitySecurityListener" /> </entity-listeners> </persistence-unit-defaults></persistence-unit-metadata>
Entity-Security mit Seam 2
public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
AuthorizationException
Entity-Security mit Seam 2
public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
AuthorizationException
Zwei Methoden notwendig
Entity-Security mit Seam 2
public List<Student> find(Teacher lecturer) { …}
public List<Student> find(Student fellow) { …}
Entity-Security mit Seam 2
public List<Student> find(Teacher lecturer) { …}
public List<Student> find(Student fellow) { …}
Aufruf geschieht auf Basis des aktuell angemeldeten Benutzers!
Entity-Security mit Seam 2
public List<Student> findAll() { Principal caller = ejbContext.getCallerPrincipal(); if (caller instanceof Teacher) { return find((Teacher)caller); } else { return find((Student)caller); }}
Entity-Security mit Seam 2
public List<Student> findAll() { Principal caller = ejbContext.getCallerPrincipal(); if (caller instanceof Teacher) { return find((Teacher)caller); } else { return find((Student)caller); }}
Wieder Security im Code „verstreut“!
JPA Security
Security Framework für JPA• Pluggable Authentication• Authorization
– JSP- und JSF-Support– Access-Check bei CRUD-Operationen– In-Memory-Filtern von Collections– In-Database-Filtern von Queries
(JPQL und Criteria)
@Permit(access = AccessType.CREATE, rule = "lecturer = CURRENT_PRINCIPAL")@Entitypublic Course { …}
Entity-Security mit JPA Security
@Permit(access = AccessType.CREATE, rule = "lecturer = CURRENT_PRINCIPAL")@Entitypublic Course { …}
Automatischer Check bei entityManager.persist(…) oder entityManager.merge(…) oder bei
Cascading!
Entity-Security mit JPA Security
Entity-Security mit JPA Security
public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
Entity-Security mit JPA Security
public List<Student> findAll() { TypedQuery<Student> query = entityManager.createNamedQuery(…, …); return query.getResultList();}
Automatische Filterung von JPA Queries und Criterias!
@PermitAny({ @Permit(access = AccessType.READ, rule = "this IN (SELECT p" + " FROM Course course" + " JOIN course.participants p" + " WHERE course.lecturer" + " = CURRENT_PRINCIPAL)"), @Permit(…)})@Entitypublic Student { …
Entity-Security mit JPA Security
Entity-Security mit JPA Securitypersistence.xml
<persistence …> <persistence-unit name="…"> <provider>org.hibernate.ejb.HibernatePersistence</…> <properties> …
</properties> </persistence-unit></persistence>
<persistence …> <persistence-unit name="…"> <provider>net.sf.jpase…SecurePersistenceProvider</…> <properties> <property name="net.sf.jpasecurity.persistence.provider" value="org.hibernate.ejb.HibernatePersistence"/> </properties> </persistence-unit></persistence>
<persistence …> <persistence-unit name="…"> <provider>net.sf.jpase…SecurePersistenceProvider</…> <properties> …
</properties> </persistence-unit></persistence>
Entity-Security mit JPA Securitypersistence.xml
<h:outputLink value="createLesson.xhtml" rendered ="#{sec:canCreate('Lesson', course)}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Create Lesson"/>
</h:outputLink>
Kurs anlegen
Kurs ändern<h:outputLink value="editCourse.xhtml" rendered ="#{sec:canUpdate(course)}"/>
<f:param name="courseId" value="#{course.id}"/>
<h:outputText value="Edit Course"/>
</h:outputLink>
Fazit Authorization
• Methoden-basiert– Spring Security
Permissions, ACL oder EL
– DeltaSpike SecurityTypesafe über Annotations im Code
• Entity-basiert– JPA Security
automatischer Filterung in der Datenbank
Vielen Dank für Ihre Zeit.
Kontakt:
open knowledge GmbHBismarckstr. 1326122 Oldenburg
[email protected]://jpasecurity.sf.net
ArneLimburg _openknowledge
Q&A