Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2002-715
$eventId
ID of event: wwdc2002
$eventContentId
ID of session without event part: 715
$eventShortId
Shortened ID of event: wwdc02
$year
Year of session: 2002
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC02 • Session 715

WebObjects Security

WebObjects • 46:27

Learn techniques for securing page generation and direct action invocation for anonymous users, gathering credentials for authentication, just-in-time login approaches, and using digital certificates. This session also covers automatic connection to pages over SSL to sites that require privacy, and access control.

Speaker: David Neumann

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Very happy to introduce Dave Neumann. Dave Neumann: All right, thank you. Okay, this year, like I've given this a few times, this time I've got a demonstration program, but unlike last year where the program was monolithic and everything was in there because I wanted you to look in the program to see how I was doing stuff, this year I've got a separate framework that has just about all the main security stuff pulled out of it.

It's really well documented and set up with a lot of other goodies that hopefully make it production-quality code, so something you can really bite your teeth into. But I also designed it to be extensible. This talk, I'm going to go over some points, kind of like how you might do stuff, but I'm also going to maybe spend a little more time on what I did inside this particular framework to address some of these kinds of issues.

But this is the first part of the session. This is the basic stuff I'm going to be covering in terms of the granularity, privacy, resource protection, authentication, and persistent data integrity and access control. One new thing on access control, last year I also talked about row-level access control. This will be talking also about attribute-level access control on an EO.

So, getting straight to the SSL stuff, this is a kind of review, but let me go over it just quick for those who are new to this thing. WebObjects generates these partial URLs, and we do that for a reason. So we don't hard code URLs to a particular deployment piece of information like your web server. But if you need SSL and you want to guarantee that it's SSL on a page, you need this absolute URL. You need to generate HTTPS, and sometimes that can be cumbersome. So let me kind of show you one of these unexciting demos.

And I've come down here to this little test page, and I've got a secure hyperlink in a secure form. Now, at the very bottom here, it says HTTP, but the link itself says HTTPS, even though I'm coming in over HTTP. That's not a big deal, so let me just show you the...

[Transcript missing]

All right, so this is a secure form.

Normally I don't just go throw in an implementation on the screen, but since this one's so short, I want to put it up here, mainly just to give you an idea of something that you can do you might not realize you can do with just regular components. So this is the source code, but before I look at that, let's show you the template for this. Not much going on, just a form, this element, and that content in the middle.

And the declaration file for this is also pretty straightforward, but there's that binding in there called InvokeAction, and it's taking whatever action was passed into this component. And the action is being set to href. So this actually is how you can actually separate out the thing that gets invoked from the URL that represents that thing.

Not many people realize you can do that with a component. Okay, and since I can split that information out in the secure form, The href I create, instead of just the default href, which would have just been this context component action URL, I'm taking that and I'm just appending HTTPS plus a host name, which I get as a binding passed in. The same thing happens with hyperlink. OK. So, OK, enough of that. Back to the slides.

Thank you. Now having gone through all that, I actually think a better way to do SSL is through redirection. The strategy that I talked about previously is you determine some page privacy, and if a page decides it should be private, it performs a redirection. I've also seen a lot of different implementations of this where when people did that they had these side effects because they generated the page twice, or they invoked the action twice.

What I mean by that, this redirection technique, is they came in over HTTP, and the naive way to do this is just take a look at the URL that's in the current world request and just throw back a redirect page and set that URL of the redirect to the exact same URL you came in on. What I do in the framework is if you come in over HTTP and the page decides it should be private, you're going to have to do a redirection.

It redirects you not to the action it came in, but to a special direct action called SSL return. That action goes and recovers the page and then tells it to render itself. The page never even renders, and the action that called it will never get invoked twice with the setup in the framework I've got.

There's a lot of other ways you can do it, Now, I don't have any silver bullets for detecting SSL. I basically do this kind of algorithm inside the framework. I look for certain headers, certain things at a port. But a given deployment's going to have a different way of doing this.

So I've basically set it up so in the framework you can specify and override how it's doing it, and augment this with maybe your own custom thing specific to your site. Maybe you don't have any headers. Maybe you run SSL on a certain port, or maybe you do have certain headers. Whatever. However you get it, that's sort of factored out from the rest of it.

So back over to this box. Thanks. All right. Now, just show it in action here. This page right now is currently over HTTP, and I want to go to the login page. OK. So The link that took me to that page was an HTTP link, but when the page rendered, you see I'm under a secure request. Now you can kind of get into a philosophical argument.

I could have just come into this page over HTTP or HTTPS, might not matter, and I might make this form in here a secure form, using that widget I just showed you a minute ago where the URL embedded in the form is an absolute URL with HTTPS on it, and that would guarantee that the stuff in these text fields would get sent to the server securely.

But the user isn't convinced of that. The user doesn't know he's in SSL. So I would argue that you would always want to use a redirect technique. So if you weren't in HTTP already, you'd want to make sure you were in HTTP just for the user's own feedback purpose.

So they would look at the browser and they'd go, yeah, I see the little key, I see the blue bar, I see HTTPS in the URL, I'm comfortable, I'm about to put my credit card or my credentials in over a secure link. So the way this gets set up in this particular application. Thank you.

In the SecureStore, which by the way is a full-blown, lightweight commerce application, so it's more than just a demo. I tried to actually be kind of thorough in most things, use some best practices where I could, so it would be not just a toy. But up here in this configuration file, this policy config file, there's this section here.

And up there is the policy that I established. Should deny all pages not in SSL mode. And right now it's set to no. And then all the pages to deny, not in SSL mode. So my login page, checkout page, account edit page, account sign-up page, those four guys will not render unless you come in over secure. And another flip down here, these settings, should redirect to SSL URL, SSL web server host name.

Those are the guys that tell you, should I just show an access denied page, or should I actually show an access denied page? And then I can actually attempt to get them to HTTPS by that redirect technique. So the pages on the application here, in the application, are oblivious to all this goings on.

They just have been configured that way. But there is an API on the pages so that if you implement certain methods, if you're not happy with the granularity of having stuff in a list, you can implement some methods in your pages that can make that determination whether things should be over SSL or not. So, that's that. Back to these.

Okay. If you're using SSL to begin with, the odds of someone hijacking your session are actually pretty remote because someone has to be over your shoulder. I was talking to someone right at the beginning of this talk about how unlikely it would be to have someone not notice them writing down your session ID onto a piece of paper behind them and then going off to another machine.

Although these days, since digital cameras are so small, actually it isn't entirely impossible for someone to come behind you and snap a picture, and if that session ID is anywhere on the system, they could in fact go to some other box and pretend to be you. There's various ways to handle this. The way I handle it in the framework, and it's turned on... Can I have the demo machine again? Sorry.

Thanks. The way I do it in this application is I've got a flag down here, "Should enable session hijacking protection." And actually, I'm kind of competing with the API to have the longest key name in the configuration file. Right now, I've got it set to yes, which means on every request, it checks for this cookie. And that cookie is only emitted if you successfully log in.

If you successfully log into the system, it emits this thing. And even though cookies can be spoofed and IP addresses can be spoofed, it just makes it a little bit harder for someone to grab that session ID, go to some other machine, and get in and pretend to be you without having to authenticate. So that's it for that. So back to... Okay, so protecting world resources.

These are like the most important... What are world resources? They're your pages, your direct actions. That's the kind of stuff I mean by that. And... Whoa. Oh, OK. Someone--that's a resource to protect. OK. OK, I don't--my wife must have got into my slides, so... Okay, sorry about that. See, I did get my kids in my slides. Okay.

So in addition to those resources, if you're protecting pages, you want to override append to response. And if you're protecting page creation, you'd override page with name. And if you're protecting--let me zip right ahead here--to direct actions, you'd override perform action name. Go back to page generation. I guess there's some caveats to the pluses and minuses of doing this sort of thing. The way the example framework works, it takes care of page generation protection and direct action protection.

What do I mean by that? This could get more elaborate than what I did in the framework. I tried to make it extensible to do other things, but essentially I noticed there's two types of situations. There's pages you view in an unauthenticated mode and the pages you viewed after you've logged in.

In a very similar situation with the SSL, it'd be nice if you could say, "These pages are okay to see. These direct actions are okay to invoke. But if anyone tries to invoke this direct action or somehow tries to get to this page, they don't have access." Let me go through the pros and cons here. When I first did something like this, the way I did this type of protection is I overrode page with name, page creation protection.

And that has one plus in that you don't invoke the constructor of the page. So if you had a lot of stuff, code executing the constructor of the page that was secure, you didn't want people executing it unless they were authenticated to execute that code, then it's sort of nice.

But I moved quickly to page generation protection because it's kind of nice to actually let the page get created, just write them in such a way that you don't do anything sensitive in the constructor. And then you've got this thing with some intelligence that you can actually ask questions. You can ask it, should I show you, or should I hide you, or should you be in SSL, and whatnot.

Also, if you override page with name on the application, and you've got code that's expecting to get the foobar page, and you don't hand that page back, you hand back the error page, then you're going to get class cast exceptions, you're going to get keys that aren't in the thing that's returned. You could be breaking code.

So with page generation protection, the page you ask for is the page you get. It just doesn't render. And I don't just render the page, scroll it away in the session. And then throw it back later. The way the framework works, it never calls super append response, so nothing on that page renders unless you're authenticated to do so.

For direct action protection, I do just go on the name, just the name of the direct action. So if someone tries to access foo/bar or direct action class name/something like that, in my abstract class I override perform action name. If they're not authenticated, invoke that direct action. I route them to a login response.

Actually, something about the... I'm going to forget this. I'm just going to say it now. In the frameworks, the way I constructed this stuff, I do have these abstract classes. I have an abstract direct action class, an abstract component, an abstract application. But you don't have to use my abstract superclasses. I set it up so you could have interfaces for all this stuff.

And I've got all the security meat for this type of stuff factored out into a policy object so that if you have some existing stack of classes, you can just implement my interface and call this policy object and basically glom this framework onto yours with just a bunch of one-liner methods. That's something a little tough to show like this, but it might be interesting for anyone who wants to come by afterward.

Now this isn't really, I guess, a security issue, but how many times have you had situations where the user pushes a button two or three times, or they backtrack to something, and you just don't want that thing to happen more than one time? It makes sense for them to do it once, but it doesn't make sense for them to do it twice, especially if they're only authenticated and maybe performed some action once.

So, not in the framework, but in the example app, there's some code here for detecting backtracking. Actually, maybe a better way to get this code is to go to Project Wonder, and they actually have a... some classes which took from stuff like this and have an implementation that detect backtracking, and then your page can basically do its own thing based on that. The thing that I do in the example app and that you might consider doing is that if someone backtracks, you overwrite invoke action on that page and if you don't call super and instead just return context page or null, the action does not invoke.

Nothing happens. It's just that something benign happens. The page just refreshes. What I also do on the pages where this happens, I put up a little message that says, "Please do not backtrack within the checkout assistant." So about the resource protection piece, this section in the configuration file has the security posture. It should deny all actions. Right now that's set to no. So it's only going to deny these three direct actions: the sign-in action, the one-click checkout, and edit account.

had most of the pages been secure and there were just exceptions the other way, you can flip that to a yes and then just have actions to allow. On should deny all pages, that's set to no as well, and you can see the pages to deny. I'm demanding authentication on the checkout page, the person browser page, and account edit page, and some others.

Okay, so let me just browse around here and add some products. Checkout. Okay. I'm not logged in, so... Log in. Now I am logged in, and I'm in Shipping Info, so let me actually cancel out of this, and mouse around someplace else. And then it said, "Okay, yeah, I'm ready to check out now." And then I check out, and no authentication gets demanded.

Again, the pages don't know anything about the login panel. All they know is that the name of this page happened to be dropped in a configuration file somewhere, and that's what set that up. A lot of apps I tried to make it, you know, where the, your code doesn't even have to know about it. So anyway, let's kind of go through this checkout process.

I tried to backtrack. I knew that. It didn't actually backtrack to that other page. It just refreshed the checkout page and gave that to me. So I'll just complete the purchase. There's my number. If I go to my account, I've got the order right down there. That's that little deal. Moving along.

What I kind of demoed a little bit was FrontGate and OnDemand. In commerce applications, you kind of want the OnDemand thing. You don't want to actually ask for credentials unless it's absolutely necessary. Logging in explicitly, checking out, viewing your account. But in some applications, you've got to have the login.

No matter what they do, they've got to be authenticated. But even in that case, it's still nice to have something like this framework to protect direct action. They always have to log in, but... They can bookmark stuff deep inside the application, and they can go back to it later.

They can email it to their buddy or their friend or their coworker, and they don't have to go all the way to the front and follow some big, long procedure to dial in. And they have to do all that just because of authentication. It's kind of nice to have something that'll just say, okay, these actions are protected, and if you're not logged in, boom, you'll be prompted. Otherwise, you don't have to re-navigate again.

Okay, I think I've covered that. Okay, and I went ahead and took care of that one, too. So, moving off to this authentication methods. There's a lot of different ways to gather credentials. HTML page, the HTTP panel, client certificates. The framework is set up to support all of these. So, Except biometric. I don't have a, I don't ship you a little, you know, thumb reader.

The most complex one actually turned out to be this one. I think if you've got a web app, I'm really not sure why you'd need this, except for one reason. The very last bullet there can provide element of single sign-on for a static site and HTML pages. That's true. Some people are just required. They have no choice.

They have to use this panel because that was a requirement. So if you do, then it's available. But the ultimate is really client-side certificates. If you have an opportunity to use these, it's pretty nice because passwords don't go anywhere. You don't, as a server vendor, have to store passwords in your database, or hashes, I should say.

The only thing going in the clear is the results of cryptographic operations, and the only password or passphrase that's ever introduced to the system is the one that goes straight into the user certificate right on the browser. It never leaves the system. It never leaves their desktop. So it's really nice, and I think this sort of thing is much more prevalent in Europe than it is in the States, but maybe sooner or later more people will use this kind of thing here.

This stuff is a little different than passwords. In a password, you present these credentials and then you get proved who you are on the server. But in this particular case, the whole SSL protocol just proves it for you. The login just happens, and you don't even see it happening. You either have access or you don't.

Now this other thing here, I left up here because I wanted to stress that a year ago, you had a lot of work to do to get a web server running with SSL and Apache on Mac OS X. Well now Mac OS X Server, which I have running on this laptop, makes it easy.

It's already out of the box, ready to support SSL. All I had to do was get some certificates from certificate authority. In this case, I went to Thought's website and got some test certificates. I didn't have to do anything with the WebObjects adapter. They just worked in both the secure and regular version of Apache.

And also, another really cool thing is that the Microsoft, the Apache, the Netscape, the CGI adapters, all those adapters do the right thing, and getting the certificate, asking for it using API and the web server to get it from the web server and pass it. So a lot of things I had to talk about last year and code examples I had to give last year are totally irrelevant now because it just works the way it's supposed to.

Okay. Now, in the module, the certificate authentication module that's in the framework, I do set it up so that the certificate gets all the way to you. It doesn't just live in the web server, but I set it up so the web server can get it all the way to the application. In the application, I have a hook that basically passes the Sun's X.509 certificate in it. It's not even the deprecated Sun API. It's all the brand new APIs. No more deprecation warnings. You can do with that certificate whatever you need to do.

You might not need to do anything, but what you probably should do is consult your company's certificate revocation list or go to a validation authority to check it. The more people actually use this as an authentication method, the more important this will be. But since a lot of people don't, I'll just move along.

Recording login failures. I guess this can be a lot more elaborate than just, did someone try to login and fail? There's all kinds of things which might indicate someone is trying to compromise your system. But the demo application talks about just doing it relevant to login. In essence, what I'm doing in here is, every time a failure happens, I just write an intrusion record to the database.

It's got a date, it's got a username and an IP address, and there's some configurable numbers, like maximum number of failures by IP and maximum number of failures by username. Okay, so let me just do that. I did something like this last year and I only had one shot at it, so I'm gonna try and see if it's more forgiving this time.

Okay, so, sign If I kept changing the username, it would fail after a few more. The reason it's important to do both is you don't want someone going to a whole bunch of machines and attacking you, and you don't want someone staying on one machine and trying a bunch of different usernames. So it's important to have both the IP and the username. Although again, people can spoof it, but hey, we're making it a little bit harder for them to get in.

Actually, while I got this up, I'd mentioned this thing works with I wanted to show you some of the ways this framework is set up. If you want to integrate this stuff with your application, first of all, these are the login methods right up here. There's the HTTP panel login method, HTML, and certificate. There's the abstract class, so you can slam some more in here if you want.

This is the abstract superclass you can inherit from for direct actions, the abstract component class, the abstract session. But if you don't have the luxury of doing that, you can implement the interface defined here, the direct actions and the component methods and the session methods. It's also got some cryptographic utilities, which I'll get to in a little bit. Back to this guy.

In the demo, I don't store passwords in the clear. I store hashes. I don't actually need to recover the password, I just need to compare it to which one's coming in. Whenever an account is created, the password that's passed in is hashed and only the hash is stored. If you know what hashes are, you look in the database, you can't recover the password from the hash. It just looks like gibberish. When someone authenticates, I pull it.

I'm Pull the hash from the database, hash their incoming thing, and just do a compare. But you don't have that luxury with... Credit cards. You have to--that's a piece of information that you actually need to recover the actual information in the application to do stuff. So if you do store credit cards, you need to encrypt them. And in my case, I'm using those cryptographic utilities to encrypt the credit cards using a DES triple. Let me go straight to this, because I'd rather show you here what's going on than just talking about it.

Here's the credit card EO. This thing right here is some accessor methods I added for convenience. Decrypted CC number, set decrypted CC number. This is the thing that's in the clear. Well, it comes in over SSL, but still, it's a readable number. What it does is, if it's non-null, it uses this utility on the CryptoUtilities, which calls this method here, and that's implemented using the cryptographic extensions on the JRE.

[Transcript missing]

So that's probably the next question. Okay, you've encrypted all this stuff, but your key's sitting right there. So if I hack this system, I've got a database of-and I hack your database, and I hack your system, I get this list of encrypted credit card numbers. But if I can get access to that, I can still encrypt it. So your kind of point of failure is this secret key right here.

So the way the industry has-there's stuff out there for hiding secret keys. You can use these tokens. These-Crystallis has one. Incypher. There's like several of these things on the market which store the key inside some module which isn't even on your system. And they have to be like FIPS, whatever, compliant. You can't even physically open the things up without destroying them, that kind of thing. Some are just smart cards.

The point is, if you've got it on the system, it's not just a file sitting there you can just pull off. If someone hacked into the system remotely, it'd be very, very difficult for them to get to the key. But that leaves us with one other way of getting at the information.

[Transcript missing]

There's almost no way to stop that, except one way. And if you've ever started up an SSL web server, at least the version of iPlanet on Windows, when you start it up, by default you have to enter a passphrase to unlock the secret key that it's going to use to do SSL. And the reason they do that is they don't want any form of password on the machine. So that means if it dies and it falls over, it's going to be a problem.

You've got to have someone on call with a pager who's going to be able to resurrect the system by providing credentials to launch a thing. I wish I could tell you there was a better way to do that, but... Maybe there is. Maybe I can do one of those things where I ask you guys a question, but it seems like in the industry, they just say, hey, provide me some credentials. You can sometimes do these things remotely over SSH and whatnot, but it's sort of a sticky problem. Yeah, thanks.

Now, this kind of gets to the meat of things. I don't want to spend too much time on-- I'll review this briefly, but I want to kind of dive into the code examples. But this is basically about the degree of access control after they log in. Everything I've talked about so far is, are you logged in or not? And if you're not, what can you see, what can't you see? But now you're logged in. We've got a user. It's not some anonymous thing. We've got a user, and we've got something you're editing.

So what do you get to do with it? And these are some examples of some API you might have or stick on your EOs that might implement some of these kinds of rules. But what's the implementation? What logic goes into deciding whether you can see or edit something?

[Transcript missing]

is in the demo.

I've written, actually, my own access control implementations, but the one in the demo doesn't use something like this. It uses a This session also covers automatic connection to pages over SSL to sites that require privacy, and access control. This session also covers automatic connection to pages over SSL to sites that require privacy, and access control. I'll show that in a second.

Before I get to that, let me get to this guy. You've made your EO smart. Your EOs know whether or not they can see or edit each other, but now you have to somehow present this in the user interface. This is kind of like the password thing where you start up the SSL web server. There's not a slam dunk on this. You can make the EOs smart. You can make them know whether or not they can read and write to each other, but at some point you need something to present that information.

Depending on the How fast just your designer people are, what they dictate or what they don't dictate, it could be a difficult problem. You could have just conditionals sprayed all over the place, depending on what's going on. But if you could possibly get away with it, it's nice to have a slightly smart component, like a smart text field or a smart string that sort of has a woe text field or a woe string in it that takes a user as a binding and the other stuff you would have just handed to the text field and just renders itself in a different way, depending on what's going on. Thank you.

But sometimes it's even worse than that. Sometimes not only do you have to protect the given EO, but even if you have access to see a certain enterprise object, maybe you don't have access to see certain attributes. In the example in the demo app, what I have in it, it shows you an example of protecting clusters of attributes.

Basically, on a person, you get to see the address, the first name, and the last name, but you need to have... Access or a- you have to have special access in order to get to the password or username or social security number, that kind of thing. So, let me show that.

First of all, let me show you this protected object. All the EOs in this particular model that have access control enabled inherit from this My Protected Object EO. And here are my primitive-- actually, the most primitive method is this one down here. But from the slide, you saw can read and can't show. This has is readable and is writable. And a person goes in as an argument.

Right beneath that is the more primitive one, which takes a user and a Java Security ACL permission object. And what I did was I've actually got a table in this model The, uh, my permission, which is in EO, it's stored, it doesn't have very much in it right now, uh, just, um, read, write, and upload, but you can imagine sticking other permissions in there, okay, all kinds of different permissions. Also, there's this MyACL entry, which has state in it, but this particular EO implements the Java ACL interface, security ACL interface.

and ProtectedObjects does what it does right here. All the meat of this, all the checking and how it determines whether you have access rights or not, is done right there in that line where it asks its ACL implementation to check a permission. And that ACL implementation is constructed right here. That's a Java Security ACL permission object. I didn't even provide the implementation, really. I just provided these cover methods, which then called into this thing.

What does that look like in action? Let's go to Products. Okay. I'm logged in as the administrator, and he's the current target for all these ACL things. And of the things that have been fetched right now, what I'm just showing here for illustration purposes is what I can do with it, and the access control list associated with it. Unlike the previous version of this, I've made it a little bit smarter, so it doesn't just look at the user.

In order to figure out if you can read or write something for a given user, it looks at if there's an ACL for that user, but also looks at all the groups the user has, and then figures it out based on that. In this particular case, we've got user, M.

Neumann can upload, or can't upload, that's what the negative means. Anyone in the contract group can write. Anyone in the marketing group can read. This person called Poulter, a user, can read, that first guy. Now, since this particular user, admin, is in the marketing and contractor group, that's where I get the read-write from. So what if I change that? So let's just take out marketing.

This is a thing right up here, just a reusable component. I just made it purely functional. You might create your own variation on it, which looks a little bit prettier. It's a generic ACL component. I used to edit ACLs throughout the system. Once you've got something like this, once you're protecting EOs, you might want to use it to protect pages. You might do it this way. You might have a table that's pretty simple. It's just got page names in it.

Hanging off of each of those rows in that table is an array of ACL entries. What you can do is you might create a table in your model using this stuff. Everything else is pretty much the same. You add that table, and like product here, you add this too-many relationship to the My ACL Entries table.

Right here. Boom. You basically would have some pretty fancy access control on the pages. Essentially what I'm saying, you could subclass my implementation of this access protection stuff, call the superclass to do all the stuff whether you're logged in or not. But if you are logged in, you might go one extra step before showing that page.

You might go and take a look at the user, because you've got a user now, and use this information about the page. Get the page and just see, does this person have, is it readable, writable? All the logic on my protected object would still work. Basically, you could go throughout the application and say, "Okay, marketing sees these pages. These guys get to see these pages." If you're a marketer, but you're also a contractor, you don't get to see it.

That kind of stuff. You could get down to that granularity. And it really would be pretty easy. And the pages--the nice thing is the pages, we don't even have to know about it. The only thing that would be changed would be one method inside this policy object in order to pull that off, so.

I guess one last thing I want to show on this is the attribute level stuff. So, kind of explain my approach there. There's these two entities in the model here, attribute entity and attribute cluster. And there's a... There's a one-to-many between a cluster and an entry. And these entities are, right now, in a demo, they're islands. No other EOs have relationships to them. So, my approach to attribute-level security is, here's a cluster of attributes. And that's what's represented by attribute cluster. And the cluster is represented by all the rows in the attribute entity.

One thing I wanted to get away from was having to have one of these In this session, we'll be talking about how to create a database that allows you to create all the types of things for every single row in the database. Most of the time, if you've got a given entity of something, it doesn't matter which row you're talking about, these three things you can't see, these three things you can't see, and that's just it for every row in the table. By default, it works that way. You've seen the model. Let me go to the application itself and show you what these things look like when they're actually running. Back down here to Attributes, and I'll edit the private attributes.

I've given it a name. That's the entity it's associated with, in this case, person. And these are all the private attributes on person. So what happens if I go to persons and I try to edit it? So I'll try to edit this fellow named Andy.

[Transcript missing]

This is great. How come that never happens when you're practicing? That never happened once. Okay. All right. I'll just log in again here.

Attributes Private. Okay. And I want to take out one of these.

[Transcript missing]

Something's going on that didn't... So I'll probably have to restart the thing. But I don't have time for that, so. I'll go back to the slides and just explain what I wanted to show you there. One thing I've done in the Enterprise Objects, I have a method on them that returns all the attribute clusters.

Right now, it just turns around and gets all the attribute clusters on an entity-by-entity basis. But it's set up that you could establish a relationship from any given EO. to this attribute cluster thing and do this attribute level security at a row-by-row basis. Now, I'm not sure when that would be necessary, but I've actually had some customers where this row of information for the administrator, no one could see anything no matter what it was unless they had certain rules. And then for all these customers, marketing could see some stuff, but some other group couldn't see this other stuff.

And then yet for some even more rows, if there were users in the system, the rules were again different. So that's what I wanted to show you with the very last step there, but didn't quite get there. To sum up this stuff, I talked about protecting privacy through SSL, some custom components, redirection, detection. I talked about protecting resources of various kinds, and showed a few kinds of authentication. The kind of authentication I didn't show was certificate, but it's in the system.

As far as persistent data integrity, we talked about using hashing and encryption and actually what to do with these secret keys on your system if you do use them. And then access control, ACLs, EOs, and entities. There's actually quite a bit more code I'd like to show, but again, I'm not sure it's best to show that like this. I might have to do it more interactively with you all. The code behind all this isn't up on any FTP servers now, but it should be there, I think, within a week after the talk.

These are kind of the places where you can get some more information about this stuff. I think this is in the slides that you'll get copies of, so I'll just move along to this. And you've seen that many times this week. And you've definitely seen that many times this week.

So I want to just get to the Q&A. And I think you know about the beta. Even if you've been on the beta before, you've got to get up here to get on the new one. And I guess there is still something left in the lab today. And I guess that's next. That's the very last thing in the developer conference. Okay. I think you've seen that stuff before, Bob and Tony.