2121import static java .util .Objects .requireNonNull ;
2222
2323import java .util .List ;
24+ import java .util .function .Predicate ;
2425
2526import org .jooby .Err ;
2627import org .jooby .Request ;
4344import org .slf4j .Logger ;
4445import org .slf4j .LoggerFactory ;
4546
47+ import javaslang .CheckedFunction1 ;
48+
4649public class AuthFilter implements Route .Handler {
4750
51+ @ SuppressWarnings ("rawtypes" )
52+ private static final Predicate <Client > useSession = c -> c instanceof IndirectClient ;
53+
4854 /** The logging system. */
4955 private final Logger log = LoggerFactory .getLogger (getClass ());
5056
@@ -67,54 +73,62 @@ public String getName() {
6773 return clientName ;
6874 }
6975
70- @ SuppressWarnings ({"rawtypes" , " unchecked" })
76+ @ SuppressWarnings ({"unchecked" })
7177 @ Override
72- public void handle (final Request req , final Response rsp ) throws Exception {
78+ public void handle (final Request req , final Response rsp ) throws Throwable {
7379 Clients clients = req .require (Clients .class );
7480 String clientName = req .param (clients .getClientNameParameter ()).value (this .clientName );
7581
7682 WebContext ctx = req .require (WebContext .class );
7783 ClientFinder finder = req .require (ClientFinder .class );
7884 AuthStore <UserProfile > store = req .require (AuthStore .class );
7985
80- Client client = find (finder , clients , ctx , null , clientName );
81-
82- boolean useSession = client instanceof IndirectClient ;
83-
84- String profileId = profileID (useSession , req );
85- UserProfile profile = profileId == null ? null : store .get (profileId ).orElse (null );
86-
87- if (profile == null ) {
88- if (client instanceof DirectClient ) {
89- log .debug ("Performing authentication for client: {}" , client );
90- try {
91- Credentials credentials = client .getCredentials (ctx );
92- log .debug ("credentials: {}" , credentials );
93- profile = client .getUserProfile (credentials , ctx );
94- log .debug ("profile: {}" , profile );
95- if (profile != null ) {
96- req .set (Auth .ID , profile .getId ());
97- store .set (profile );
86+ // stateless or previously authenticated stateful
87+ UserProfile profile = find (finder , clients , ctx , null , clientName , client -> {
88+ String profileId = profileID (useSession .test (client ), req );
89+ UserProfile identity = profileId == null ? null : store .get (profileId ).orElse (null );
90+
91+ if (identity == null ) {
92+ if (client instanceof DirectClient ) {
93+ log .debug ("Performing authentication for client: {}" , client );
94+ try {
95+ Credentials credentials = client .getCredentials (ctx );
96+ log .debug ("credentials: {}" , credentials );
97+ identity = client .getUserProfile (credentials , ctx );
98+ log .debug ("profile: {}" , identity );
99+ if (identity != null ) {
100+ req .set (Auth .ID , identity .getId ());
101+ req .set (Auth .CNAME , client .getName ());
102+ store .set (identity );
103+ }
104+ } catch (RequiresHttpAction e ) {
105+ throw new TechnicalException ("Unexpected HTTP action" , e );
98106 }
99- } catch (RequiresHttpAction e ) {
100- throw new TechnicalException ("Unexpected HTTP action" , e );
101107 }
102108 }
103- }
109+ return identity ;
110+ });
104111
105112 if (profile == null ) {
106- if (useSession ) {
107- // indirect client, start authentication
108- try {
109- final String requestedUrl = ctx .getFullRequestURL ();
110- log .debug ("requestedUrl: {}" , requestedUrl );
111- ctx .setSessionAttribute (Pac4jConstants .REQUESTED_URL , requestedUrl );
112- client .redirect (ctx , true );
113- rsp .end ();
114- } catch (RequiresHttpAction ex ) {
115- new AuthResponse (rsp ).handle (client , ex );
113+ // try stateful auth
114+ Boolean redirected = find (finder , clients , ctx , null , clientName , client -> {
115+ if (useSession .test (client )) {
116+ // indirect client, start authentication
117+ try {
118+ final String requestedUrl = ctx .getFullRequestURL ();
119+ log .debug ("requestedUrl: {}" , requestedUrl );
120+ ctx .setSessionAttribute (Pac4jConstants .REQUESTED_URL , requestedUrl );
121+ client .redirect (ctx , true );
122+ rsp .end ();
123+ } catch (RequiresHttpAction ex ) {
124+ new AuthResponse (rsp ).handle (client , ex );
125+ }
126+ return Boolean .TRUE ;
127+ } else {
128+ return null ;
116129 }
117- } else {
130+ });
131+ if (redirected != Boolean .TRUE ) {
118132 throw new Err (Status .UNAUTHORIZED );
119133 }
120134 } else {
@@ -129,13 +143,19 @@ private String profileID(final boolean useSession, final Request req) {
129143 }
130144
131145 @ SuppressWarnings ("rawtypes" )
132- private Client find (final ClientFinder finder , final Clients clients , final WebContext ctx ,
133- final Class <? extends Client <?, ?>> clientType , final String clientName ) {
146+ private <T > T find (final ClientFinder finder , final Clients clients , final WebContext ctx ,
147+ final Class <? extends Client <?, ?>> clientType , final String clientName ,
148+ final CheckedFunction1 <Client , T > fn ) throws Throwable {
149+
134150 List <Client > result = finder .find (clients , ctx , clientName );
135- if (result .size () > 0 ) {
136- return result .get (0 );
151+ for (Client client : result ) {
152+ T value = fn .apply (client );
153+ if (value != null ) {
154+ return value ;
155+ }
137156 }
138- throw new Err (Status .UNAUTHORIZED );
157+
158+ return null ;
139159 }
140160
141161 @ SuppressWarnings ("rawtypes" )
0 commit comments