File: user-authentication.xml

package info (click to toggle)
libspring-ldap-java 1.3.1.RELEASE-5
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 2,872 kB
  • sloc: java: 12,509; xml: 4,106; jsp: 36; makefile: 33; sh: 13
file content (235 lines) | stat: -rw-r--r-- 9,626 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="user-authentication">
  <title>User Authentication using Spring LDAP</title>

  <sect1>
    <title>Basic Authentication</title>

    <para>While the core functionality of the <literal>ContextSource</literal>
    is to provide <literal>DirContext</literal> instances for use by
    <literal>LdapTemplate</literal>, it may also be used for authenticating
    users against an LDAP server. The <literal>getContext(principal,
    credentials)</literal> method of <literal>ContextSource</literal> will do
    exactly that; construct a <literal>DirContext</literal> instance according
    to the <literal>ContextSource</literal> configuration, authenticating the
    context using the supplied principal and credentials. A custom
    authenticate method could look like this:</para>

    <para><programlisting>public boolean authenticate(String userDn, String credentials) {
  DirContext ctx = null;
  try {
    ctx = contextSource.getContext(userDn, credentials);
    return true;
  } catch (Exception e) {
    // Context creation failed - authentication did not succeed
    logger.error("Login failed", e);
    return false;
  } finally {
    // It is imperative that the created DirContext instance is always closed
    LdapUtils.closeContext(ctx);
  }
}</programlisting>The userDn supplied to the <literal>authenticate</literal>
    method needs to be the full DN of the user to authenticate (regardless of
    the <literal>base</literal> setting on the
    <literal>ContextSource</literal>). You will typically need to perform an
    LDAP search based on e.g. the user name to get this DN:</para>

    <para><programlisting>private String getDnForUser(String uid) {
  Filter f = new EqualsFilter("uid", uid);
  List result = ldapTemplate.search(DistinguishedName.EMPTY_PATH, f.toString(),
      new AbstractContextMapper() {
    protected Object doMapFromContext(DirContextOperations ctx) {
      return ctx.getNameInNamespace();
    }
  });
  
  if(result.size() != 1) {
    throw new RuntimeException("User not found or not unique");
  }
  
  return (String)result.get(0);
}</programlisting>There are some drawbacks to this approach. The user is
    forced to concern herself with the DN of the user, she can only search for
    the user's uid, and the search always starts at the root of the tree (the
    empty path). A more flexible method would let the user specify the search
    base, the search filter, and the credentials. Spring LDAP 1.3.0 introduced
    new authenticate methods in LdapTemplate that provide this
    functionality:</para>

    <itemizedlist>
      <listitem>
        <para><literal>boolean authenticate(Name base, String filter, String
        password);</literal></para>
      </listitem>

      <listitem>
        <para><literal>boolean authenticate(String base, String filter, String
        password);</literal></para>
      </listitem>
    </itemizedlist>

    <para>Using one of these methods, authentication becomes as simple as
    this:</para>

    <para><example>
        <title>Authenticating a user using Spring LDAP.</title>

        <programlisting>boolean authenticated = ldapTemplate.authenticate("", "(uid=john.doe)", "secret");</programlisting>
      </example></para>

    <tip>
      <para>Don't write your own custom authenticate methods. Use the ones
      provided in Spring LDAP 1.3.x.</para>
    </tip>
  </sect1>

  <sect1>
    <title>Performing Operations on the Authenticated Context</title>

    <para>Some authentication schemes and LDAP servers require some operation
    to be performed on the created <literal>DirContext</literal> instance for
    the actual authentication to occur. You should test and make sure how your
    server setup and authentication schemes behave; failure to do so might
    result in that users will be admitted into your system regardless of the
    DN/credentials supplied. This is a naïve implementation of an authenticate
    method where a hard-coded <literal>lookup</literal> operation is performed
    on the authenticated context:</para>

    <para><programlisting>public boolean authenticate(String userDn, String credentials) {
  DirContext ctx = null;
  try {
    ctx = contextSource.getContext(userDn, credentials);
    // Take care here - if a base was specified on the ContextSource
    // that needs to be removed from the user DN for the lookup to succeed.
<emphasis role="bold">    ctx.lookup(userDn);</emphasis>    
    return true;
  } catch (Exception e) {
    // Context creation failed - authentication did not succeed
    logger.error("Login failed", e);
    return false;
  } finally {
    // It is imperative that the created DirContext instance is always closed
    LdapUtils.closeContext(ctx);
  }
}</programlisting>It would be better if the operation could be provided as an
    implementation of a callback interface, thus not limiting the operation to
    always be a <literal>lookup</literal>. Spring LDAP 1.3.0 introduced the
    callback interface
    <literal>AuthenticatedLdapEntryContextCallback</literal> and a few
    corresponding <literal>authenticate</literal> methods:</para>

    <itemizedlist>
      <listitem>
        <para><literal>boolean authenticate(Name base, String filter, String
        password, AuthenticatedLdapEntryContextCallback
        callback);</literal></para>
      </listitem>

      <listitem>
        <para><literal>boolean authenticate(String base, String filter, String
        password, AuthenticatedLdapEntryContextCallback
        callback);</literal></para>
      </listitem>
    </itemizedlist>

    <para>This opens up for any operation to be performed on the authenticated
    context:</para>

    <example>
      <title>Performing an LDAP operation on the authenticated context using
      Spring LDAP.</title>

      <programlisting>AuthenticatedLdapEntryContextCallback contextCallback = new AuthenticatedLdapEntryContextCallback() {
  public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
    try {
      ctx.lookup(ldapEntryIdentification.getRelativeDn());
    }
    catch (NamingException e) {
      throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeDn(), e);
    }
  }
};

ldapTemplate.authenticate("", "(uid=john.doe)", "secret", contextCallback));</programlisting>
    </example>
  </sect1>

  <sect1>
    <title>Retrieving the Authentication Exception</title>

    <para>So far, the methods have only been able to tell the user whether or
    not the authentication succeeded. There has been no way of retrieving the
    actual exception. Spring LDAP 1.3.1 introduced the
    <literal>AuthenticationErrorCallback</literal> and a few more
    <literal>authenticate</literal> methods:</para>

    <itemizedlist>
      <listitem>
        <para><literal>boolean authenticate(Name base, String filter, String
        password, AuthenticationErrorCallback errorCallback);</literal></para>
      </listitem>

      <listitem>
        <para><literal>boolean authenticate(String base, String filter, String
        password, AuthenticationErrorCallback errorCallback);</literal></para>
      </listitem>

      <listitem>
        <para><literal>boolean authenticate(Name base, String filter, String
        password, AuthenticatedLdapEntryContextCallback callback,
        AuthenticationErrorCallback errorCallback);</literal></para>
      </listitem>

      <listitem>
        <para><literal>boolean authenticate(String base, String filter, String
        password, AuthenticatedLdapEntryContextCallback callback,
        AuthenticationErrorCallback errorCallback);</literal></para>
      </listitem>
    </itemizedlist>

    <para>A convenient collecting implementation of the error callback
    interface is also provided:</para>

    <para><programlisting>public final class CollectingAuthenticationErrorCallback implements AuthenticationErrorCallback {
  private Exception error;

  public void execute(Exception e) {
    this.error = e;
  }

  public Exception getError() {
    return error;
  }
}</programlisting>The code needed for authenticating a user and retrieving the
    authentication exception in case of an error boils down to this:</para>

    <para><example>
        <title>Authenticating a user and retrieving the authentication
        exception.</title>

        <programlisting>import org.springframework.ldap.core.support.CollectingAuthenticationErrorCallback;
...
CollectingAuthenticationErrorCallback errorCallback = new CollectingAuthenticationErrorCallback();
boolean result = ldapTemplate.authenticate("", filter.toString(), "invalidpassword", errorCallback);
if (!result) {
  Exception error = errorCallback.getError();
  // error is likely of type org.springframework.ldap.AuthenticationException
}</programlisting>
      </example></para>
  </sect1>

  <sect1>
    <title>Use Spring Security</title>

    <para>While the approach above may be sufficient for simple authentication
    scenarios, requirements in this area commonly expand rapidly. There is a
    multitude of aspects that apply, including authentication, authorization,
    web integration, user context management, etc. If you suspect that the
    requirements might expand beyond just simple authentication, you should
    definitely consider using <ulink type=""
    url="http://static.springsource.org/spring-security/site/">Spring
    Security</ulink> for your security purposes instead. It is a full-blown,
    mature security framework addressing the above aspects as well as several
    others.</para>
  </sect1>
</chapter>