Skip to content

Commit 6460d04

Browse files
committed
Revert "docs: add JackieNim as a contributor (iluwatar#1749)"
This reverts commit 1dd2628
1 parent 9f0c1f9 commit 6460d04

19 files changed

+458
-2
lines changed

facet/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
layout: pattern
3+
title: Facet
4+
folder: facet
5+
permalink: /patterns/facet/
6+
categories: Behavioural
7+
tags:
8+
- Security
9+
---
10+
11+
## Intent
12+
13+
Use facet pattern to realize security, in order to ensure some privillage only can be granted to some certain users.
14+
15+
## Explanation
16+
17+
Real world example
18+
19+
> Lets say if some client can only be able to read information of an object, then the client should be provided with a read-only facet and for write operation should be forbiddened.
20+
21+
Wikipedia says
22+
23+
> Facets are used as a security pattern in CapabilityOrientedProgramming, in order to satisfy the PrincipleOfLeastAuthority.
24+
25+
**Programmatic Example**
26+
27+
For a facet, use method to create, query the registered class and set the registered class.
28+
```java
29+
public abstract class Facet {
30+
public static Facet create();
31+
public static Class[] query(Facet f, Class[] interfaces);
32+
public static Facet narrow(Facet f, Class[] interfaces);
33+
}
34+
```
35+
For a sentry, use method to connect the facet and context to make request.
36+
```java
37+
public interface Sentry {
38+
public abstract boolean execute(User user, Class interfaceClass);
39+
}
40+
```
41+
For the context, it abstracts the logic for make access control decisions on behalf of a Facet.
42+
```java
43+
public interface Context {
44+
public boolean validateInterface(Class interfaceClass);
45+
}
46+
```
47+
After validation, execute the method.
48+
```java
49+
public interface SecurityMethods {
50+
public static String delegate(User user);
51+
}
52+
```
53+
54+
## Class Diagram
55+
56+
![alt text](./etc/facet.urm.png "Facet pattern class diagram")
57+
58+
## Applicability
59+
60+
Use the Facet pattern when you care about the privilege for different user.
61+
62+
* restrict an interface to obtain a smaller interface that provides less authority.
63+
64+
## Real world examples
65+
66+
* [java.sql.Connection](https://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html)

facet/etc/facet.urm.png

137 KB
Loading

facet/etc/facet.urm.puml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
@startuml
2+
package com.iluwatar.facet {
3+
class AccessController {
4+
+ AccessController()
5+
+ checkPermission(user : User) : boolean {static}
6+
}
7+
class Administrator {
8+
+ Administrator()
9+
}
10+
class App {
11+
- LOGGER : Logger {static}
12+
+ App()
13+
+ main(args : String[]) {static}
14+
}
15+
class Client {
16+
+ Client()
17+
}
18+
interface Context {
19+
+ setUser(User) {abstract}
20+
+ validateInterface(Class<T>) : boolean {abstract}
21+
}
22+
class CurrentContext {
23+
- user : User
24+
+ CurrentContext()
25+
+ setUser(user : User)
26+
+ validateInterface(interfaceClass : Class<T>) : boolean
27+
}
28+
class DefaultSentry {
29+
- context : Context
30+
+ DefaultSentry(context : Context)
31+
+ execute(user : User, interfaceClass : Class<T>) : boolean
32+
}
33+
class Facet {
34+
- classes : Class[]
35+
- sentry : Sentry
36+
- user : User
37+
- Facet()
38+
+ create(sentry : Sentry, classes : Class[]) : Facet {static}
39+
+ invokeSecurityMethod(interfaceClass : Class<T>) : String
40+
+ narrow(facet : Facet, interfaces : Class[]) : Facet {static}
41+
+ query(facet : Facet) : Class[] {static}
42+
+ setUser(user : User)
43+
}
44+
interface SecurityMethods {
45+
+ delegate(user : User) : String {static}
46+
}
47+
class SecurityMethodsImplementation {
48+
+ SecurityMethodsImplementation()
49+
+ delegate(user : User) : String {static}
50+
}
51+
interface Sentry {
52+
+ context : Context {static}
53+
+ execute(User, Class<T>) : boolean {abstract}
54+
}
55+
interface User {
56+
}
57+
}
58+
DefaultSentry --> "-context" Context
59+
Facet --> "-sentry" Sentry
60+
CurrentContext --> "-user" User
61+
Sentry --> "-context" Context
62+
Facet --> "-user" User
63+
Administrator ..|> User
64+
Client ..|> User
65+
CurrentContext ..|> Context
66+
DefaultSentry ..|> Sentry
67+
SecurityMethodsImplementation ..|> SecurityMethods
68+
@enduml

compose-method/pom.xml renamed to facet/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<artifactId>java-design-patterns</artifactId>
3232
<version>1.25.0-SNAPSHOT</version>
3333
</parent>
34-
<artifactId>compose-method</artifactId>
34+
<artifactId>facet</artifactId>
3535
<dependencies>
3636
<dependency>
3737
<groupId>org.junit.jupiter</groupId>
@@ -49,7 +49,7 @@
4949
<configuration>
5050
<archive>
5151
<manifest>
52-
<mainClass>com.iluwatar.compose-method.App</mainClass>
52+
<mainClass>com.iluwatar.facet.App</mainClass>
5353
</manifest>
5454
</archive>
5555
</configuration>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* to control the permission.
5+
*/
6+
public class AccessController {
7+
private AccessController() {
8+
throw new IllegalStateException("utility class");
9+
}
10+
11+
/**
12+
* check the permission to use the method.
13+
*
14+
* @param user the identity of the user.
15+
* @return boolean to judge whether can use the method.
16+
*/
17+
public static boolean checkPermission(User user) {
18+
if (user == null) {
19+
return false;
20+
} else if (user instanceof Administrator) {
21+
return true;
22+
} else if (user instanceof Client) {
23+
return false;
24+
}
25+
return false;
26+
}
27+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* the administrator.
5+
*/
6+
public class Administrator implements User {
7+
public Administrator() {
8+
//admin information.
9+
}
10+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.iluwatar.facet;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
5+
/**
6+
* use client and administrator to check whether it can successfully secure.
7+
* for the client, it wants to execute the secured method. Then the facet will ask
8+
* the sentry to validate the execution. But because the identity is user,
9+
* it requirement is illegal. So the result is null. For admin to execute the
10+
* secured method. It will be executed.
11+
*/
12+
@Slf4j
13+
public class App {
14+
/**
15+
* Program entry point.
16+
*
17+
* @param args command line args.
18+
*/
19+
public static void main(String[] args) {
20+
var clientSentry = new DefaultSentry(new CurrentContext());
21+
var clientFacet = Facet.create(clientSentry, new Class[0]);
22+
Facet.narrow(clientFacet, new Class[]{SecurityMethods.class});
23+
clientFacet.setUser(new Client());
24+
var administratorSentry = new DefaultSentry(new CurrentContext());
25+
var administratorFacet =
26+
Facet.create(administratorSentry, new Class[0]);
27+
Facet.narrow(administratorFacet, new Class[]{SecurityMethods.class});
28+
administratorFacet.setUser(new Administrator());
29+
LOGGER.info("client invoke result: {}",
30+
clientFacet.invokeSecurityMethod(SecurityMethods.class));
31+
LOGGER.info("administrator invoke result: {}",
32+
administratorFacet.invokeSecurityMethod(SecurityMethods.class));
33+
LOGGER.info("client classes: {}", Facet.query(clientFacet));
34+
LOGGER.info("admin classes: {}", Facet.query(administratorFacet));
35+
}
36+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* The client.
5+
*/
6+
public class Client implements User {
7+
public Client() {
8+
//client information.
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* A Context abstracts the logic for making access control decisions on behalf of a Facet.
5+
*/
6+
public interface Context {
7+
public boolean validateInterface(Class<? extends SecurityMethods> interfaceClass);
8+
9+
public void setUser(User user);
10+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* Current context used to abstract the logic for making access control decisions
5+
* on behalf of a Facet.
6+
*/
7+
public class CurrentContext implements Context {
8+
@Override
9+
public boolean validateInterface(Class<? extends SecurityMethods> interfaceClass) {
10+
if (interfaceClass.equals(SecurityMethods.class)) {
11+
return AccessController.checkPermission(user);
12+
}
13+
return true;
14+
}
15+
16+
private User user;
17+
18+
public void setUser(User user) {
19+
this.user = user;
20+
}
21+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* The default sentry is to consider the interface and context being
5+
* used to make the request and selects one of its comprising objects to handle it.
6+
*/
7+
public class DefaultSentry implements Sentry {
8+
private final Context context;
9+
10+
public DefaultSentry(Context context) {
11+
this.context = context;
12+
}
13+
14+
15+
@Override
16+
public boolean execute(User user, Class<? extends SecurityMethods> interfaceClass) {
17+
this.context.setUser(user);
18+
return this.context.validateInterface(interfaceClass);
19+
}
20+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* implements a set of interfaces and it is exposed to the user.
5+
*/
6+
public class Facet {
7+
private final Sentry sentry;
8+
private Class<? extends SecurityMethods>[] classes;
9+
private User user;
10+
11+
/**
12+
* create a facet.
13+
*
14+
* @param sentry set sentry corresponds to such facet.
15+
* @param classes set supported interfaces for this facet.
16+
* @return created facet.
17+
*/
18+
public static Facet create(Sentry sentry, Class<? extends SecurityMethods>[] classes) {
19+
return new Facet(sentry, classes);
20+
}
21+
22+
private Facet(Sentry sentry, Class<? extends SecurityMethods>[] classes) {
23+
this.sentry = sentry;
24+
this.classes = classes;
25+
}
26+
27+
public static Class<? extends SecurityMethods>[] query(Facet facet) {
28+
return facet.classes;
29+
}
30+
31+
public void setUser(User user) {
32+
this.user = user;
33+
}
34+
35+
public static Facet narrow(Facet facet, Class<? extends SecurityMethods>[] interfaces) {
36+
facet.classes = interfaces.clone();
37+
return facet;
38+
}
39+
40+
/**
41+
* invoke method.
42+
*
43+
* @param interfaceClass the interface for the class.
44+
* @return the result of this invoke.
45+
*/
46+
public String invokeSecurityMethod(Class<? extends SecurityMethods> interfaceClass) {
47+
for (var j = 0; j < this.classes.length; j++) {
48+
if (interfaceClass.equals(classes[j]) && this.sentry.execute(this.user, interfaceClass)) {
49+
return SecurityMethodsImplementation.delegate(user);
50+
}
51+
}
52+
return null;
53+
}
54+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* the interface for security methods.
5+
*/
6+
public interface SecurityMethods {
7+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* implementation of the secure method.
5+
*/
6+
public class SecurityMethodsImplementation implements SecurityMethods {
7+
private SecurityMethodsImplementation() {
8+
throw new IllegalStateException("utility class");
9+
}
10+
11+
/**
12+
* the method to be secured.
13+
*
14+
* @param user according to different user to return different result.
15+
* @return the execution result of this method.
16+
*/
17+
public static String delegate(User user) {
18+
if (user instanceof Client) {
19+
return "Client create something.";
20+
} else if (user instanceof Administrator) {
21+
return "Administrator create something.";
22+
}
23+
return "";
24+
}
25+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.iluwatar.facet;
2+
3+
/**
4+
* The sentry interface to consider the interface and context being
5+
* used to make the request and select one of its comprising objects to handle it.
6+
*/
7+
public interface Sentry {
8+
public abstract boolean execute(User user, Class<? extends SecurityMethods> interfaceClass);
9+
}

0 commit comments

Comments
 (0)