22namespace FormatD \HmacAuthentication \Authentication ;
33
44
5+ use FormatD \HmacAuthentication \Domain \Model \HmacToken ;
6+ use FormatD \HmacAuthentication \Service \HmacService ;
57use Neos \Flow \Annotations as Flow ;
68use Neos \Flow \Security \Account ;
79use Neos \Flow \Security \AccountRepository ;
8- use Neos \Flow \Security \Authentication \Token \UsernamePassword ;
9- use Neos \Flow \Security \Authentication \Token \UsernamePasswordHttpBasic ;
10+ use Neos \Flow \Security \Authentication \TokenAndProviderFactoryInterface ;
1011use Neos \Flow \Security \Authentication \TokenInterface ;
1112use Neos \Flow \Security \Context ;
12- use Neos \Flow \Security \Cryptography \HashService ;
1313use Neos \Flow \Security \Exception \UnsupportedAuthenticationTokenException ;
1414
1515/**
@@ -31,6 +31,12 @@ class UsernameHmacTimestampProvider extends \Neos\Flow\Security\Authentication\P
3131 */
3232 protected $ hmacService ;
3333
34+ /**
35+ * @Flow\Inject
36+ * @var TokenAndProviderFactoryInterface
37+ */
38+ protected $ tokenAndProviderFactory ;
39+
3440 /**
3541 * @var Context
3642 * @Flow\Inject
@@ -43,6 +49,12 @@ class UsernameHmacTimestampProvider extends \Neos\Flow\Security\Authentication\P
4349 */
4450 protected $ persistenceManager ;
4551
52+ /**
53+ * @Flow\InjectConfiguration(package="FormatD.HmacAuthentication.allowedAuthenticationProviders")
54+ * @var array
55+ */
56+ protected $ allowedAuthenticationProviders ;
57+
4658 /**
4759 * Returns the class names of the tokens this provider can authenticate.
4860 *
@@ -53,6 +65,43 @@ public function getTokenClassNames()
5365 return [UsernameHmacTimestampToken::class];
5466 }
5567
68+ /**
69+ * @param string $alias
70+ * @return false|string
71+ */
72+ protected function getAuthenticationProviderNameByAlias ($ alias ) {
73+ if (!is_array ($ this ->allowedAuthenticationProviders )) {
74+ return false ;
75+ }
76+ if (!key_exists ($ alias , $ this ->allowedAuthenticationProviders )) {
77+ return false ;
78+ }
79+ $ name = $ this ->allowedAuthenticationProviders [$ alias ];
80+ return strlen ($ name ) > 0 ? $ name : false ;
81+ }
82+
83+ /**
84+ * @param HmacToken $hmacToken
85+ */
86+ protected function getAuthenticationProviderNameWithHmacToken ($ hmacToken ) {
87+ if ($ hmacToken ->hasPayloadEntry (HmacService::HTK_Provider)) {
88+ $ tokenAuthenticationProviderAlias = $ hmacToken ->getPayloadEntry (HmacService::HTK_Provider);
89+ if ($ authenticationProviderName = $ this ->getAuthenticationProviderNameByAlias ($ tokenAuthenticationProviderAlias )) {
90+ return $ authenticationProviderName ;
91+ }
92+ }
93+
94+ return $ this ->options ['mainAuthenticationProviderName ' ] ? $ this ->options ['mainAuthenticationProviderName ' ] : $ this ->name ;
95+ }
96+
97+ /**
98+ * @param HmacToken $hmacToken
99+ * @return mixed
100+ */
101+ protected function getUsernameFromHmacToken ($ hmacToken ) {
102+ return $ hmacToken ->getPayloadEntry (HmacService::HTK_Username);
103+ }
104+
56105 /**
57106 * Checks the given token for validity and sets the token authentication status
58107 * accordingly (success, wrong credentials or no credentials given).
@@ -76,31 +125,35 @@ public function authenticate(TokenInterface $authenticationToken)
76125 $ authenticationToken ->setAuthenticationStatus (TokenInterface::NO_CREDENTIALS_GIVEN );
77126 }
78127
79- if (!is_array ($ credentials ) || !isset ($ credentials [' username ' ]) || ! isset ( $ credentials [ ' hmac ' ]) || ! isset ( $ credentials [ ' timestamp ' ])) {
128+ if (!is_array ($ credentials ) || !isset ($ credentials [UsernameHmacTimestampToken:: CRED_TOKEN ])) {
80129 return ;
81130 }
82131
83- $ providerName = $ this ->options ['mainAuthenticationProviderName ' ] ? $ this ->options ['mainAuthenticationProviderName ' ] : $ this ->name ;
132+ $ hmacToken = HmacToken::FromJson ($ credentials [UsernameHmacTimestampToken::CRED_TOKEN ]);
133+
134+ $ providerName = $ this ->getAuthenticationProviderNameWithHmacToken ($ hmacToken );
135+ $ userName = $ this ->getUsernameFromHmacToken ($ hmacToken );
136+
84137 $ accountRepository = $ this ->accountRepository ;
85- $ this ->securityContext ->withoutAuthorizationChecks (function () use ($ credentials , $ providerName , $ accountRepository , &$ account ) {
86- $ account = $ accountRepository ->findActiveByAccountIdentifierAndAuthenticationProviderName ($ credentials [ ' username ' ] , $ providerName );
138+ $ this ->securityContext ->withoutAuthorizationChecks (function () use ($ credentials , $ userName , $ providerName , $ accountRepository , &$ account ) {
139+ $ account = $ accountRepository ->findActiveByAccountIdentifierAndAuthenticationProviderName ($ userName , $ providerName );
87140 });
88141
89142 $ authenticationToken ->setAuthenticationStatus (TokenInterface::WRONG_CREDENTIALS );
90143
144+ $ isHmacTokenValid = $ this ->hmacService ->validateToken ($ hmacToken );
145+
91146 if ($ account === null ) {
92- // validate anyway to prevent timing attacks
93- $ this ->hmacService ->validateHmac ($ credentials ['username ' ], $ credentials ['timestamp ' ], $ credentials ['hmac ' ]);
147+ // Return after token hmac validation to prevent timing attacks
94148 return ;
95149 }
96150
97- if ($ this -> hmacService -> validateHmac ( $ credentials [ ' username ' ], $ credentials [ ' timestamp ' ], $ credentials [ ' hmac ' ]) ) {
151+ if ($ isHmacTokenValid ) {
98152 $ account ->authenticationAttempted (TokenInterface::AUTHENTICATION_SUCCESSFUL );
99153 $ authenticationToken ->setAuthenticationStatus (TokenInterface::AUTHENTICATION_SUCCESSFUL );
100154 $ authenticationToken ->setAccount ($ account );
101- } else {
102- $ account ->authenticationAttempted (TokenInterface::WRONG_CREDENTIALS );
103155 }
156+
104157 $ this ->accountRepository ->update ($ account );
105158 $ this ->persistenceManager ->whitelistObject ($ account );
106159 }
0 commit comments