View Javadoc
1   /*
2    * MIT License
3    *
4    * Copyright (c) 2010-2022 The Waffle Project Contributors: https://github.com/Waffle/waffle/graphs/contributors
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy
7    * of this software and associated documentation files (the "Software"), to deal
8    * in the Software without restriction, including without limitation the rights
9    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10   * copies of the Software, and to permit persons to whom the Software is
11   * furnished to do so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  package waffle.shiro.negotiate;
25  
26  import java.security.Principal;
27  
28  /**
29   * Derived from net.skorgenes.security.jsecurity.negotiate.NegotiateAuthenticationFilter. see:
30   *
31   * https://bitbucket.org/lothor
32   *
33   * /shiro-negotiate/src/7b25efde130b/src/main/java/net/skorgenes/security/jsecurity/negotiate
34   *
35   * /NegotiateAuthenticationRealm.java?at=default
36   *
37   * @author Dan Rollo
38   */
39  import javax.security.auth.Subject;
40  
41  import org.apache.shiro.authc.AuthenticationException;
42  import org.apache.shiro.authc.AuthenticationInfo;
43  import org.apache.shiro.authc.AuthenticationToken;
44  import org.apache.shiro.realm.AuthenticatingRealm;
45  import org.slf4j.Logger;
46  import org.slf4j.LoggerFactory;
47  
48  import waffle.servlet.WindowsPrincipal;
49  import waffle.windows.auth.IWindowsAuthProvider;
50  import waffle.windows.auth.IWindowsIdentity;
51  import waffle.windows.auth.IWindowsSecurityContext;
52  import waffle.windows.auth.impl.WindowsAuthProviderImpl;
53  
54  /**
55   * The Class NegotiateAuthenticationRealm.
56   */
57  public class NegotiateAuthenticationRealm extends AuthenticatingRealm {
58  
59      /**
60       * This class's private logger.
61       */
62      private static final Logger LOGGER = LoggerFactory.getLogger(NegotiateAuthenticationRealm.class);
63  
64      /** The windows auth provider. */
65      private final IWindowsAuthProvider windowsAuthProvider;
66  
67      /**
68       * Instantiates a new negotiate authentication realm.
69       */
70      public NegotiateAuthenticationRealm() {
71          this.windowsAuthProvider = new WindowsAuthProviderImpl();
72      }
73  
74      @Override
75      public boolean supports(final AuthenticationToken token) {
76          return token instanceof NegotiateToken;
77      }
78  
79      @Override
80      protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken t) {
81  
82          final NegotiateToken token = (NegotiateToken) t;
83          final byte[] inToken = token.getIn();
84  
85          if (token.isNtlmPost()) {
86              // type 2 NTLM authentication message received
87              this.windowsAuthProvider.resetSecurityToken(token.getConnectionId());
88          }
89  
90          final IWindowsSecurityContext securityContext;
91          try {
92              securityContext = this.windowsAuthProvider.acceptSecurityToken(token.getConnectionId(), inToken,
93                      token.getSecurityPackage());
94          } catch (final Exception e) {
95              NegotiateAuthenticationRealm.LOGGER.warn("error logging in user");
96              throw new AuthenticationException(e);
97          }
98  
99          final byte[] continueTokenBytes = securityContext.getToken();
100         token.setOut(continueTokenBytes);
101         if (continueTokenBytes != null) {
102             NegotiateAuthenticationRealm.LOGGER.debug("continue token bytes: {}",
103                     Integer.valueOf(continueTokenBytes.length));
104         } else {
105             NegotiateAuthenticationRealm.LOGGER.debug("no continue token bytes");
106         }
107 
108         if (securityContext.isContinue() || token.isNtlmPost()) {
109             throw new AuthenticationInProgressException();
110         }
111 
112         final IWindowsIdentity windowsIdentity = securityContext.getIdentity();
113         securityContext.dispose();
114 
115         NegotiateAuthenticationRealm.LOGGER.debug("logged in user: {} ({})", windowsIdentity.getFqn(),
116                 windowsIdentity.getSidString());
117 
118         final Principal principal = new WindowsPrincipal(windowsIdentity);
119         token.setPrincipal(principal);
120 
121         final Subject subject = new Subject();
122         subject.getPrincipals().add(principal);
123         token.setSubject(subject);
124 
125         return token.createInfo();
126     }
127 
128 }