Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6a74a50493 | ||
![]() |
8c27f20534 | ||
![]() |
29c6003ea3 | ||
![]() |
ae34fc7c2b | ||
![]() |
2a5d5d43b0 | ||
![]() |
e6a4670ba9 | ||
![]() |
64d64b4099 | ||
![]() |
88f9a10f21 | ||
![]() |
4e08d4f8fd | ||
![]() |
1c4dda9299 | ||
![]() |
ab18fa5832 | ||
![]() |
484d0c0882 | ||
![]() |
be59c3615f | ||
![]() |
db351f7771 | ||
![]() |
91c29c4092 | ||
![]() |
415b97535e | ||
![]() |
7d1272d815 | ||
![]() |
c9ba0b13f8 | ||
![]() |
fadd9f6168 | ||
![]() |
395e2e2a85 | ||
![]() |
6335084835 | ||
![]() |
eab336cd3d | ||
![]() |
f4691fca1f | ||
![]() |
341d4fbae5 | ||
![]() |
e467b45ab1 | ||
![]() |
7edfad3486 | ||
![]() |
80578b88ac | ||
![]() |
5646e7a0e7 | ||
![]() |
53a592ef63 | ||
![]() |
3337dbd0a4 | ||
![]() |
82a2a42f84 | ||
![]() |
ac49b5bb70 | ||
![]() |
926ab07c07 | ||
![]() |
7a2dbea019 | ||
![]() |
dff50097e8 | ||
![]() |
aff9d3af20 | ||
![]() |
02eb1d6677 | ||
![]() |
78a673e4ad | ||
![]() |
e0d8644264 | ||
![]() |
d8c662eaad | ||
![]() |
6d1d259f71 | ||
![]() |
2841853d37 | ||
![]() |
360dd3c3bd | ||
![]() |
c6add0cca6 | ||
![]() |
7ac6252aac | ||
![]() |
5d2d1c342b | ||
![]() |
6da0a85936 | ||
![]() |
116972d725 |
42
app/package-lock.json
generated
42
app/package-lock.json
generated
@@ -9,7 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^0.17.0",
|
"@authorizerdev/authorizer-react": "^0.25.0",
|
||||||
"@types/react": "^17.0.15",
|
"@types/react": "^17.0.15",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"esbuild": "^0.12.17",
|
"esbuild": "^0.12.17",
|
||||||
@@ -26,9 +26,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-js": {
|
"node_modules/@authorizerdev/authorizer-js": {
|
||||||
"version": "0.10.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.14.0.tgz",
|
||||||
"integrity": "sha512-REM8FLD/Ej9gzA2zDGDAke6QFss33ubePlTDmLDmIYUuQmpHFlO5mCCS6nVsKkN7F/Bcwkmp+eUNQjkdGCaKLg==",
|
"integrity": "sha512-cpeeFrmG623QPLn+nf+ACHayZYqW8xokIidGikeboBDJtuAAQB50a54/7HwLHriG2FB7WvPuHQ/9LFFX//N1lg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-fetch": "^2.6.1"
|
"node-fetch": "^2.6.1"
|
||||||
},
|
},
|
||||||
@@ -37,11 +37,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-react": {
|
"node_modules/@authorizerdev/authorizer-react": {
|
||||||
"version": "0.17.0",
|
"version": "0.25.0",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.25.0.tgz",
|
||||||
"integrity": "sha512-7WcNCU7hDFkVfFb8LcJXFwWiLYd8aY78z1AbNPxCa2Cw5G85PaRkzjKybP6h01ITVOHO6M03lLwPj8p6Sr6fEg==",
|
"integrity": "sha512-Dt2rZf+cGCVb8dqcJ/9l8Trx+QeXnTdfhER6r/cq0iOnFC9MqWzQPB3RgrlUoMLHtZvKNDXIk1HvfD5hSX9lhw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^0.10.0",
|
"@authorizerdev/authorizer-js": "^0.14.0",
|
||||||
"final-form": "^4.20.2",
|
"final-form": "^4.20.2",
|
||||||
"react-final-form": "^6.5.3",
|
"react-final-form": "^6.5.3",
|
||||||
"styled-components": "^5.3.0"
|
"styled-components": "^5.3.0"
|
||||||
@@ -816,7 +816,7 @@
|
|||||||
"node_modules/tr46": {
|
"node_modules/tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.5",
|
||||||
@@ -838,12 +838,12 @@
|
|||||||
"node_modules/webidl-conversions": {
|
"node_modules/webidl-conversions": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||||
},
|
},
|
||||||
"node_modules/whatwg-url": {
|
"node_modules/whatwg-url": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tr46": "~0.0.3",
|
"tr46": "~0.0.3",
|
||||||
"webidl-conversions": "^3.0.0"
|
"webidl-conversions": "^3.0.0"
|
||||||
@@ -852,19 +852,19 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": {
|
"@authorizerdev/authorizer-js": {
|
||||||
"version": "0.10.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.14.0.tgz",
|
||||||
"integrity": "sha512-REM8FLD/Ej9gzA2zDGDAke6QFss33ubePlTDmLDmIYUuQmpHFlO5mCCS6nVsKkN7F/Bcwkmp+eUNQjkdGCaKLg==",
|
"integrity": "sha512-cpeeFrmG623QPLn+nf+ACHayZYqW8xokIidGikeboBDJtuAAQB50a54/7HwLHriG2FB7WvPuHQ/9LFFX//N1lg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"node-fetch": "^2.6.1"
|
"node-fetch": "^2.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@authorizerdev/authorizer-react": {
|
"@authorizerdev/authorizer-react": {
|
||||||
"version": "0.17.0",
|
"version": "0.25.0",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.25.0.tgz",
|
||||||
"integrity": "sha512-7WcNCU7hDFkVfFb8LcJXFwWiLYd8aY78z1AbNPxCa2Cw5G85PaRkzjKybP6h01ITVOHO6M03lLwPj8p6Sr6fEg==",
|
"integrity": "sha512-Dt2rZf+cGCVb8dqcJ/9l8Trx+QeXnTdfhER6r/cq0iOnFC9MqWzQPB3RgrlUoMLHtZvKNDXIk1HvfD5hSX9lhw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@authorizerdev/authorizer-js": "^0.10.0",
|
"@authorizerdev/authorizer-js": "^0.14.0",
|
||||||
"final-form": "^4.20.2",
|
"final-form": "^4.20.2",
|
||||||
"react-final-form": "^6.5.3",
|
"react-final-form": "^6.5.3",
|
||||||
"styled-components": "^5.3.0"
|
"styled-components": "^5.3.0"
|
||||||
@@ -1482,7 +1482,7 @@
|
|||||||
"tr46": {
|
"tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.5",
|
||||||
@@ -1497,12 +1497,12 @@
|
|||||||
"webidl-conversions": {
|
"webidl-conversions": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||||
},
|
},
|
||||||
"whatwg-url": {
|
"whatwg-url": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tr46": "~0.0.3",
|
"tr46": "~0.0.3",
|
||||||
"webidl-conversions": "^3.0.0"
|
"webidl-conversions": "^3.0.0"
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
"author": "Lakhan Samani",
|
"author": "Lakhan Samani",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^0.17.0",
|
"@authorizerdev/authorizer-react": "^0.25.0",
|
||||||
"@types/react": "^17.0.15",
|
"@types/react": "^17.0.15",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"esbuild": "^0.12.17",
|
"esbuild": "^0.12.17",
|
||||||
|
@@ -72,11 +72,13 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
|||||||
</Footer>
|
</Footer>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
{config.is_sign_up_enabled && (
|
{config.is_basic_authentication_enabled &&
|
||||||
<FooterContent>
|
!config.is_magic_link_login_enabled &&
|
||||||
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
config.is_sign_up_enabled && (
|
||||||
</FooterContent>
|
<FooterContent>
|
||||||
)}
|
Don't have an account? <Link to="/app/signup"> Sign Up</Link>
|
||||||
|
</FooterContent>
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
12
dashboard/package-lock.json
generated
12
dashboard/package-lock.json
generated
@@ -2529,7 +2529,8 @@
|
|||||||
"@chakra-ui/css-reset": {
|
"@chakra-ui/css-reset": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz",
|
||||||
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg=="
|
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@chakra-ui/descendant": {
|
"@chakra-ui/descendant": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@@ -3133,7 +3134,8 @@
|
|||||||
"@graphql-typed-document-node/core": {
|
"@graphql-typed-document-node/core": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
|
||||||
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg=="
|
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@popperjs/core": {
|
"@popperjs/core": {
|
||||||
"version": "2.11.0",
|
"version": "2.11.0",
|
||||||
@@ -3843,7 +3845,8 @@
|
|||||||
"react-icons": {
|
"react-icons": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
||||||
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ=="
|
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
@@ -4029,7 +4032,8 @@
|
|||||||
"use-callback-ref": {
|
"use-callback-ref": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
||||||
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg=="
|
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"use-sidecar": {
|
"use-sidecar": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
|
@@ -71,6 +71,18 @@ const Features = ({ variables, setVariables }: any) => {
|
|||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex>
|
||||||
|
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||||
|
<Text fontSize="sm">Disable Strong Password:</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex justifyContent="start" mb={3}>
|
||||||
|
<InputField
|
||||||
|
variables={variables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={SwitchInputType.DISABLE_STRONG_PASSWORD}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -9,7 +9,13 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { FaGoogle, FaGithub, FaFacebookF } from 'react-icons/fa';
|
import {
|
||||||
|
FaGoogle,
|
||||||
|
FaGithub,
|
||||||
|
FaFacebookF,
|
||||||
|
FaLinkedin,
|
||||||
|
FaApple,
|
||||||
|
} from 'react-icons/fa';
|
||||||
import { TextInputType, HiddenInputType } from '../../constants';
|
import { TextInputType, HiddenInputType } from '../../constants';
|
||||||
|
|
||||||
const OAuthConfig = ({
|
const OAuthConfig = ({
|
||||||
@@ -182,6 +188,82 @@ const OAuthConfig = ({
|
|||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
h="35px"
|
||||||
|
marginRight="1.5%"
|
||||||
|
border="1px solid #3b5998"
|
||||||
|
borderRadius="5px"
|
||||||
|
>
|
||||||
|
<FaLinkedin style={{ color: '#3b5998' }} />
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.LINKEDIN_CLIENT_ID}
|
||||||
|
placeholder="LinkedIn Client ID"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
fieldVisibility={fieldVisibility}
|
||||||
|
setFieldVisibility={setFieldVisibility}
|
||||||
|
inputType={HiddenInputType.LINKEDIN_CLIENT_SECRET}
|
||||||
|
placeholder="LinkedIn Client Secret"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
h="35px"
|
||||||
|
marginRight="1.5%"
|
||||||
|
border="1px solid #3b5998"
|
||||||
|
borderRadius="5px"
|
||||||
|
>
|
||||||
|
<FaApple style={{ color: '#3b5998' }} />
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.APPLE_CLIENT_ID}
|
||||||
|
placeholder="Apple Client ID"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
fieldVisibility={fieldVisibility}
|
||||||
|
setFieldVisibility={setFieldVisibility}
|
||||||
|
inputType={HiddenInputType.APPLE_CLIENT_SECRET}
|
||||||
|
placeholder="Apple CLient Secret"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,67 +1,68 @@
|
|||||||
import React from "react";
|
import React from 'react';
|
||||||
import { Flex, Stack, Center, Text, useMediaQuery } from "@chakra-ui/react";
|
import { Flex, Stack, Center, Text, useMediaQuery } from '@chakra-ui/react';
|
||||||
import { ArrayInputType } from "../../constants";
|
import { ArrayInputType } from '../../constants';
|
||||||
import InputField from "../InputField";
|
import InputField from '../InputField';
|
||||||
|
|
||||||
const Roles = ({ variables, setVariables }: any) => {
|
const Roles = ({ variables, setVariables }: any) => {
|
||||||
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)");
|
const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
|
||||||
return (
|
|
||||||
<div>
|
return (
|
||||||
{" "}
|
<div>
|
||||||
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
{' '}
|
||||||
Roles
|
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
|
||||||
</Text>
|
Roles
|
||||||
<Stack spacing={6} padding="2% 0%">
|
</Text>
|
||||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
<Stack spacing={6} padding="2% 0%">
|
||||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
<Text fontSize="sm">Roles:</Text>
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
</Flex>
|
<Text fontSize="sm">Roles:</Text>
|
||||||
<Center
|
</Flex>
|
||||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
<Center
|
||||||
mt={isNotSmallerScreen ? "0" : "2"}
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
overflow="hidden"
|
mt={isNotSmallerScreen ? '0' : '2'}
|
||||||
>
|
overflow="hidden"
|
||||||
<InputField
|
>
|
||||||
borderRadius={7}
|
<InputField
|
||||||
variables={variables}
|
borderRadius={7}
|
||||||
setVariables={setVariables}
|
variables={variables}
|
||||||
inputType={ArrayInputType.ROLES}
|
setVariables={setVariables}
|
||||||
/>
|
inputType={ArrayInputType.ROLES}
|
||||||
</Center>
|
/>
|
||||||
</Flex>
|
</Center>
|
||||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
</Flex>
|
||||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
<Text fontSize="sm">Default Roles:</Text>
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
</Flex>
|
<Text fontSize="sm">Default Roles:</Text>
|
||||||
<Center
|
</Flex>
|
||||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
<Center
|
||||||
mt={isNotSmallerScreen ? "0" : "2"}
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
>
|
mt={isNotSmallerScreen ? '0' : '2'}
|
||||||
<InputField
|
>
|
||||||
variables={variables}
|
<InputField
|
||||||
setVariables={setVariables}
|
variables={variables}
|
||||||
inputType={ArrayInputType.DEFAULT_ROLES}
|
setVariables={setVariables}
|
||||||
/>
|
inputType={ArrayInputType.DEFAULT_ROLES}
|
||||||
</Center>
|
/>
|
||||||
</Flex>
|
</Center>
|
||||||
<Flex direction={isNotSmallerScreen ? "row" : "column"}>
|
</Flex>
|
||||||
<Flex w="30%" justifyContent="start" alignItems="center">
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
<Text fontSize="sm">Protected Roles:</Text>
|
<Flex w="30%" justifyContent="start" alignItems="center">
|
||||||
</Flex>
|
<Text fontSize="sm">Protected Roles:</Text>
|
||||||
<Center
|
</Flex>
|
||||||
w={isNotSmallerScreen ? "70%" : "100%"}
|
<Center
|
||||||
mt={isNotSmallerScreen ? "0" : "2"}
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
>
|
mt={isNotSmallerScreen ? '0' : '2'}
|
||||||
<InputField
|
>
|
||||||
variables={variables}
|
<InputField
|
||||||
setVariables={setVariables}
|
variables={variables}
|
||||||
inputType={ArrayInputType.PROTECTED_ROLES}
|
setVariables={setVariables}
|
||||||
/>
|
inputType={ArrayInputType.PROTECTED_ROLES}
|
||||||
</Center>
|
/>
|
||||||
</Flex>
|
</Center>
|
||||||
</Stack>
|
</Flex>
|
||||||
</div>
|
</Stack>
|
||||||
);
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Roles;
|
export default Roles;
|
||||||
|
@@ -7,6 +7,8 @@ export const TextInputType = {
|
|||||||
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
|
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
|
||||||
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
|
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
|
||||||
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
|
||||||
|
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
|
||||||
|
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
|
||||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||||
REDIS_URL: 'REDIS_URL',
|
REDIS_URL: 'REDIS_URL',
|
||||||
SMTP_HOST: 'SMTP_HOST',
|
SMTP_HOST: 'SMTP_HOST',
|
||||||
@@ -31,6 +33,8 @@ export const HiddenInputType = {
|
|||||||
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
|
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
|
||||||
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
|
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
|
||||||
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
|
||||||
|
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
|
||||||
|
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||||
JWT_SECRET: 'JWT_SECRET',
|
JWT_SECRET: 'JWT_SECRET',
|
||||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||||
@@ -63,6 +67,7 @@ export const SwitchInputType = {
|
|||||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||||
|
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DateInputType = {
|
export const DateInputType = {
|
||||||
@@ -99,6 +104,10 @@ export interface envVarTypes {
|
|||||||
GITHUB_CLIENT_SECRET: string;
|
GITHUB_CLIENT_SECRET: string;
|
||||||
FACEBOOK_CLIENT_ID: string;
|
FACEBOOK_CLIENT_ID: string;
|
||||||
FACEBOOK_CLIENT_SECRET: string;
|
FACEBOOK_CLIENT_SECRET: string;
|
||||||
|
LINKEDIN_CLIENT_ID: string;
|
||||||
|
LINKEDIN_CLIENT_SECRET: string;
|
||||||
|
APPLE_CLIENT_ID: string;
|
||||||
|
APPLE_CLIENT_SECRET: string;
|
||||||
ROLES: [string] | [];
|
ROLES: [string] | [];
|
||||||
DEFAULT_ROLES: [string] | [];
|
DEFAULT_ROLES: [string] | [];
|
||||||
PROTECTED_ROLES: [string] | [];
|
PROTECTED_ROLES: [string] | [];
|
||||||
@@ -123,6 +132,7 @@ export interface envVarTypes {
|
|||||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||||
DISABLE_SIGN_UP: boolean;
|
DISABLE_SIGN_UP: boolean;
|
||||||
|
DISABLE_STRONG_PASSWORD: boolean;
|
||||||
OLD_ADMIN_SECRET: string;
|
OLD_ADMIN_SECRET: string;
|
||||||
DATABASE_NAME: string;
|
DATABASE_NAME: string;
|
||||||
DATABASE_TYPE: string;
|
DATABASE_TYPE: string;
|
||||||
|
@@ -26,9 +26,13 @@ export const EnvVariablesQuery = `
|
|||||||
GITHUB_CLIENT_SECRET,
|
GITHUB_CLIENT_SECRET,
|
||||||
FACEBOOK_CLIENT_ID,
|
FACEBOOK_CLIENT_ID,
|
||||||
FACEBOOK_CLIENT_SECRET,
|
FACEBOOK_CLIENT_SECRET,
|
||||||
ROLES,
|
LINKEDIN_CLIENT_ID,
|
||||||
|
LINKEDIN_CLIENT_SECRET,
|
||||||
|
APPLE_CLIENT_ID,
|
||||||
|
APPLE_CLIENT_SECRET,
|
||||||
DEFAULT_ROLES,
|
DEFAULT_ROLES,
|
||||||
PROTECTED_ROLES,
|
PROTECTED_ROLES,
|
||||||
|
ROLES,
|
||||||
JWT_TYPE,
|
JWT_TYPE,
|
||||||
JWT_SECRET,
|
JWT_SECRET,
|
||||||
JWT_ROLE_CLAIM,
|
JWT_ROLE_CLAIM,
|
||||||
@@ -49,6 +53,7 @@ export const EnvVariablesQuery = `
|
|||||||
DISABLE_EMAIL_VERIFICATION,
|
DISABLE_EMAIL_VERIFICATION,
|
||||||
DISABLE_BASIC_AUTHENTICATION,
|
DISABLE_BASIC_AUTHENTICATION,
|
||||||
DISABLE_SIGN_UP,
|
DISABLE_SIGN_UP,
|
||||||
|
DISABLE_STRONG_PASSWORD,
|
||||||
DISABLE_REDIS_FOR_ENV,
|
DISABLE_REDIS_FOR_ENV,
|
||||||
CUSTOM_ACCESS_TOKEN_SCRIPT,
|
CUSTOM_ACCESS_TOKEN_SCRIPT,
|
||||||
DATABASE_NAME,
|
DATABASE_NAME,
|
||||||
|
@@ -46,6 +46,10 @@ const Environment = () => {
|
|||||||
GITHUB_CLIENT_SECRET: '',
|
GITHUB_CLIENT_SECRET: '',
|
||||||
FACEBOOK_CLIENT_ID: '',
|
FACEBOOK_CLIENT_ID: '',
|
||||||
FACEBOOK_CLIENT_SECRET: '',
|
FACEBOOK_CLIENT_SECRET: '',
|
||||||
|
LINKEDIN_CLIENT_ID: '',
|
||||||
|
LINKEDIN_CLIENT_SECRET: '',
|
||||||
|
APPLE_CLIENT_ID: '',
|
||||||
|
APPLE_CLIENT_SECRET: '',
|
||||||
ROLES: [],
|
ROLES: [],
|
||||||
DEFAULT_ROLES: [],
|
DEFAULT_ROLES: [],
|
||||||
PROTECTED_ROLES: [],
|
PROTECTED_ROLES: [],
|
||||||
@@ -70,6 +74,7 @@ const Environment = () => {
|
|||||||
DISABLE_EMAIL_VERIFICATION: false,
|
DISABLE_EMAIL_VERIFICATION: false,
|
||||||
DISABLE_BASIC_AUTHENTICATION: false,
|
DISABLE_BASIC_AUTHENTICATION: false,
|
||||||
DISABLE_SIGN_UP: false,
|
DISABLE_SIGN_UP: false,
|
||||||
|
DISABLE_STRONG_PASSWORD: false,
|
||||||
OLD_ADMIN_SECRET: '',
|
OLD_ADMIN_SECRET: '',
|
||||||
DATABASE_NAME: '',
|
DATABASE_NAME: '',
|
||||||
DATABASE_TYPE: '',
|
DATABASE_TYPE: '',
|
||||||
@@ -83,6 +88,8 @@ const Environment = () => {
|
|||||||
GOOGLE_CLIENT_SECRET: false,
|
GOOGLE_CLIENT_SECRET: false,
|
||||||
GITHUB_CLIENT_SECRET: false,
|
GITHUB_CLIENT_SECRET: false,
|
||||||
FACEBOOK_CLIENT_SECRET: false,
|
FACEBOOK_CLIENT_SECRET: false,
|
||||||
|
LINKEDIN_CLIENT_SECRET: false,
|
||||||
|
APPLE_CLIENT_SECRET: false,
|
||||||
JWT_SECRET: false,
|
JWT_SECRET: false,
|
||||||
SMTP_PASSWORD: false,
|
SMTP_PASSWORD: false,
|
||||||
ADMIN_SECRET: false,
|
ADMIN_SECRET: false,
|
||||||
|
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "authorizer",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
18
server/constants/auth_methods.go
Normal file
18
server/constants/auth_methods.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
||||||
|
AuthRecipeMethodBasicAuth = "basic_auth"
|
||||||
|
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
||||||
|
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
||||||
|
// AuthRecipeMethodGoogle is the google auth method
|
||||||
|
AuthRecipeMethodGoogle = "google"
|
||||||
|
// AuthRecipeMethodGithub is the github auth method
|
||||||
|
AuthRecipeMethodGithub = "github"
|
||||||
|
// AuthRecipeMethodFacebook is the facebook auth method
|
||||||
|
AuthRecipeMethodFacebook = "facebook"
|
||||||
|
// AuthRecipeMethodLinkedin is the linkedin auth method
|
||||||
|
AuthRecipeMethodLinkedIn = "linkedin"
|
||||||
|
// AuthRecipeMethodApple is the apple auth method
|
||||||
|
AuthRecipeMethodApple = "apple"
|
||||||
|
)
|
@@ -19,4 +19,8 @@ const (
|
|||||||
DbTypeMariaDB = "mariadb"
|
DbTypeMariaDB = "mariadb"
|
||||||
// DbTypeCassandra is the cassandra database type
|
// DbTypeCassandra is the cassandra database type
|
||||||
DbTypeCassandraDB = "cassandradb"
|
DbTypeCassandraDB = "cassandradb"
|
||||||
|
// DbTypeScyllaDB is the scylla database type
|
||||||
|
DbTypeScyllaDB = "scylladb"
|
||||||
|
// DbTypeCockroachDB is the cockroach database type
|
||||||
|
DbTypeCockroachDB = "cockroachdb"
|
||||||
)
|
)
|
||||||
|
@@ -3,14 +3,8 @@ package constants
|
|||||||
var VERSION = "0.0.1"
|
var VERSION = "0.0.1"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Envstore identifier
|
// TestEnv is used for testing
|
||||||
// StringStore string store identifier
|
TestEnv = "test"
|
||||||
// StringStoreIdentifier = "stringStore"
|
|
||||||
// // BoolStore bool store identifier
|
|
||||||
// BoolStoreIdentifier = "boolStore"
|
|
||||||
// // SliceStore slice store identifier
|
|
||||||
// SliceStoreIdentifier = "sliceStore"
|
|
||||||
|
|
||||||
// EnvKeyEnv key for env variable ENV
|
// EnvKeyEnv key for env variable ENV
|
||||||
EnvKeyEnv = "ENV"
|
EnvKeyEnv = "ENV"
|
||||||
// EnvKeyEnvPath key for cli arg variable ENV_PATH
|
// EnvKeyEnvPath key for cli arg variable ENV_PATH
|
||||||
@@ -81,6 +75,14 @@ const (
|
|||||||
EnvKeyFacebookClientID = "FACEBOOK_CLIENT_ID"
|
EnvKeyFacebookClientID = "FACEBOOK_CLIENT_ID"
|
||||||
// EnvKeyFacebookClientSecret key for env variable FACEBOOK_CLIENT_SECRET
|
// EnvKeyFacebookClientSecret key for env variable FACEBOOK_CLIENT_SECRET
|
||||||
EnvKeyFacebookClientSecret = "FACEBOOK_CLIENT_SECRET"
|
EnvKeyFacebookClientSecret = "FACEBOOK_CLIENT_SECRET"
|
||||||
|
// EnvKeyLinkedinClientID key for env variable LINKEDIN_CLIENT_ID
|
||||||
|
EnvKeyLinkedInClientID = "LINKEDIN_CLIENT_ID"
|
||||||
|
// EnvKeyLinkedinClientSecret key for env variable LINKEDIN_CLIENT_SECRET
|
||||||
|
EnvKeyLinkedInClientSecret = "LINKEDIN_CLIENT_SECRET"
|
||||||
|
// EnvKeyAppleClientID key for env variable APPLE_CLIENT_ID
|
||||||
|
EnvKeyAppleClientID = "APPLE_CLIENT_ID"
|
||||||
|
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
|
||||||
|
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
|
||||||
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
||||||
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
||||||
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
||||||
@@ -113,6 +115,8 @@ const (
|
|||||||
EnvKeyDisableSignUp = "DISABLE_SIGN_UP"
|
EnvKeyDisableSignUp = "DISABLE_SIGN_UP"
|
||||||
// EnvKeyDisableRedisForEnv key for env variable DISABLE_REDIS_FOR_ENV
|
// EnvKeyDisableRedisForEnv key for env variable DISABLE_REDIS_FOR_ENV
|
||||||
EnvKeyDisableRedisForEnv = "DISABLE_REDIS_FOR_ENV"
|
EnvKeyDisableRedisForEnv = "DISABLE_REDIS_FOR_ENV"
|
||||||
|
// EnvKeyDisableStrongPassword key for env variable DISABLE_STRONG_PASSWORD
|
||||||
|
EnvKeyDisableStrongPassword = "DISABLE_STRONG_PASSWORD"
|
||||||
|
|
||||||
// Slice variables
|
// Slice variables
|
||||||
// EnvKeyRoles key for env variable ROLES
|
// EnvKeyRoles key for env variable ROLES
|
||||||
|
@@ -8,4 +8,7 @@ const (
|
|||||||
FacebookUserInfoURL = "https://graph.facebook.com/me?fields=id,first_name,last_name,name,email,picture&access_token="
|
FacebookUserInfoURL = "https://graph.facebook.com/me?fields=id,first_name,last_name,name,email,picture&access_token="
|
||||||
// Ref: https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#3-your-github-app-accesses-the-api-with-the-users-access-token
|
// Ref: https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#3-your-github-app-accesses-the-api-with-the-users-access-token
|
||||||
GithubUserInfoURL = "https://api.github.com/user"
|
GithubUserInfoURL = "https://api.github.com/user"
|
||||||
|
// Ref: https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/profile-api
|
||||||
|
LinkedInUserInfoURL = "https://api.linkedin.com/v2/me?projection=(id,localizedFirstName,localizedLastName,emailAddress,profilePicture(displayImage~:playableStreams))"
|
||||||
|
LinkedInEmailURL = "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))"
|
||||||
)
|
)
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
const (
|
|
||||||
// SignupMethodBasicAuth is the basic_auth signup method
|
|
||||||
SignupMethodBasicAuth = "basic_auth"
|
|
||||||
// SignupMethodMagicLinkLogin is the magic_link_login signup method
|
|
||||||
SignupMethodMagicLinkLogin = "magic_link_login"
|
|
||||||
// SignupMethodGoogle is the google signup method
|
|
||||||
SignupMethodGoogle = "google"
|
|
||||||
// SignupMethodGithub is the github signup method
|
|
||||||
SignupMethodGithub = "github"
|
|
||||||
// SignupMethodFacebook is the facebook signup method
|
|
||||||
SignupMethodFacebook = "facebook"
|
|
||||||
)
|
|
@@ -7,4 +7,6 @@ const (
|
|||||||
TokenTypeAccessToken = "access_token"
|
TokenTypeAccessToken = "access_token"
|
||||||
// TokenTypeIdentityToken is the identity_token token type
|
// TokenTypeIdentityToken is the identity_token token type
|
||||||
TokenTypeIdentityToken = "id_token"
|
TokenTypeIdentityToken = "id_token"
|
||||||
|
// TokenTypeSessionToken is the session_token type used for browser session
|
||||||
|
TokenTypeSessionToken = "session_token"
|
||||||
)
|
)
|
||||||
|
@@ -20,10 +20,10 @@ func InitDB() error {
|
|||||||
|
|
||||||
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
envs := memorystore.RequiredEnvStoreObj.GetRequiredEnv()
|
||||||
|
|
||||||
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB
|
isSQL := envs.DatabaseType != constants.DbTypeArangodb && envs.DatabaseType != constants.DbTypeMongodb && envs.DatabaseType != constants.DbTypeCassandraDB && envs.DatabaseType != constants.DbTypeScyllaDB
|
||||||
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
isArangoDB := envs.DatabaseType == constants.DbTypeArangodb
|
||||||
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
isMongoDB := envs.DatabaseType == constants.DbTypeMongodb
|
||||||
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB
|
isCassandra := envs.DatabaseType == constants.DbTypeCassandraDB || envs.DatabaseType == constants.DbTypeScyllaDB
|
||||||
|
|
||||||
if isSQL {
|
if isSQL {
|
||||||
log.Info("Initializing SQL Driver for: ", envs.DatabaseType)
|
log.Info("Initializing SQL Driver for: ", envs.DatabaseType)
|
||||||
|
@@ -38,7 +38,6 @@ func (user *User) AsAPIUser() *model.User {
|
|||||||
email := user.Email
|
email := user.Email
|
||||||
createdAt := user.CreatedAt
|
createdAt := user.CreatedAt
|
||||||
updatedAt := user.UpdatedAt
|
updatedAt := user.UpdatedAt
|
||||||
revokedTimestamp := user.RevokedTimestamp
|
|
||||||
return &model.User{
|
return &model.User{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
@@ -55,7 +54,7 @@ func (user *User) AsAPIUser() *model.User {
|
|||||||
PhoneNumberVerified: &isPhoneVerified,
|
PhoneNumberVerified: &isPhoneVerified,
|
||||||
Picture: user.Picture,
|
Picture: user.Picture,
|
||||||
Roles: strings.Split(user.Roles, ","),
|
Roles: strings.Split(user.Roles, ","),
|
||||||
RevokedTimestamp: revokedTimestamp,
|
RevokedTimestamp: user.RevokedTimestamp,
|
||||||
CreatedAt: &createdAt,
|
CreatedAt: &createdAt,
|
||||||
UpdatedAt: &updatedAt,
|
UpdatedAt: &updatedAt,
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
@@ -29,6 +30,8 @@ func NewProvider() (*provider, error) {
|
|||||||
dbPort := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePort
|
dbPort := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabasePort
|
||||||
if dbPort != "" && dbHost != "" {
|
if dbPort != "" && dbHost != "" {
|
||||||
dbURL = fmt.Sprintf("%s:%s", dbHost, dbPort)
|
dbURL = fmt.Sprintf("%s:%s", dbHost, dbPort)
|
||||||
|
} else if dbHost != "" {
|
||||||
|
dbURL = dbHost
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +97,8 @@ func NewProvider() (*provider, error) {
|
|||||||
NumRetries: 3,
|
NumRetries: 3,
|
||||||
}
|
}
|
||||||
cassandraClient.Consistency = gocql.LocalQuorum
|
cassandraClient.Consistency = gocql.LocalQuorum
|
||||||
|
cassandraClient.ConnectTimeout = 10 * time.Second
|
||||||
|
cassandraClient.ProtoVersion = 4
|
||||||
|
|
||||||
session, err := cassandraClient.CreateSession()
|
session, err := cassandraClient.CreateSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -68,7 +68,6 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
|||||||
opts.SetSort(bson.M{"created_at": -1})
|
opts.SetSort(bson.M{"created_at": -1})
|
||||||
|
|
||||||
paginationClone := pagination
|
paginationClone := pagination
|
||||||
// TODO add pagination total
|
|
||||||
|
|
||||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||||
count, err := userCollection.CountDocuments(nil, bson.M{}, options.Count())
|
count, err := userCollection.CountDocuments(nil, bson.M{}, options.Count())
|
||||||
|
@@ -46,7 +46,7 @@ func NewProvider() (*provider, error) {
|
|||||||
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
dbURL := memorystore.RequiredEnvStoreObj.GetRequiredEnv().DatabaseURL
|
||||||
|
|
||||||
switch dbType {
|
switch dbType {
|
||||||
case constants.DbTypePostgres, constants.DbTypeYugabyte:
|
case constants.DbTypePostgres, constants.DbTypeYugabyte, constants.DbTypeCockroachDB:
|
||||||
sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig)
|
sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig)
|
||||||
case constants.DbTypeSqlite:
|
case constants.DbTypeSqlite:
|
||||||
sqlDB, err = gorm.Open(sqlite.Open(dbURL), ormConfig)
|
sqlDB, err = gorm.Open(sqlite.Open(dbURL), ormConfig)
|
||||||
|
@@ -97,7 +97,6 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
|||||||
func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
result := p.db.Where("email = ?", email).First(&user)
|
result := p.db.Where("email = ?", email).First(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return user, result.Error
|
||||||
}
|
}
|
||||||
@@ -110,7 +109,6 @@ func (p *provider) GetUserByID(id string) (models.User, error) {
|
|||||||
var user models.User
|
var user models.User
|
||||||
|
|
||||||
result := p.db.Where("id = ?", id).First(&user)
|
result := p.db.Where("id = ?", id).First(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return user, result.Error
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,7 @@ func SendMail(to []string, Subject, bodyMessage string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if envKey == "test" {
|
if envKey == constants.TestEnv {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
m := gomail.NewMessage()
|
m := gomail.NewMessage()
|
||||||
|
46
server/env/env.go
vendored
46
server/env/env.go
vendored
@@ -68,6 +68,10 @@ func InitAllEnv() error {
|
|||||||
osGithubClientSecret := os.Getenv(constants.EnvKeyGithubClientSecret)
|
osGithubClientSecret := os.Getenv(constants.EnvKeyGithubClientSecret)
|
||||||
osFacebookClientID := os.Getenv(constants.EnvKeyFacebookClientID)
|
osFacebookClientID := os.Getenv(constants.EnvKeyFacebookClientID)
|
||||||
osFacebookClientSecret := os.Getenv(constants.EnvKeyFacebookClientSecret)
|
osFacebookClientSecret := os.Getenv(constants.EnvKeyFacebookClientSecret)
|
||||||
|
osLinkedInClientID := os.Getenv(constants.EnvKeyLinkedInClientID)
|
||||||
|
osLinkedInClientSecret := os.Getenv(constants.EnvKeyLinkedInClientSecret)
|
||||||
|
osAppleClientID := os.Getenv(constants.EnvKeyAppleClientID)
|
||||||
|
osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret)
|
||||||
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
|
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
|
||||||
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
|
||||||
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
|
||||||
@@ -79,6 +83,7 @@ func InitAllEnv() error {
|
|||||||
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
||||||
osDisableSignUp := os.Getenv(constants.EnvKeyDisableSignUp)
|
osDisableSignUp := os.Getenv(constants.EnvKeyDisableSignUp)
|
||||||
osDisableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv)
|
osDisableRedisForEnv := os.Getenv(constants.EnvKeyDisableRedisForEnv)
|
||||||
|
osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword)
|
||||||
|
|
||||||
// os slice vars
|
// os slice vars
|
||||||
osAllowedOrigins := os.Getenv(constants.EnvKeyAllowedOrigins)
|
osAllowedOrigins := os.Getenv(constants.EnvKeyAllowedOrigins)
|
||||||
@@ -345,6 +350,34 @@ func InitAllEnv() error {
|
|||||||
envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret
|
envData[constants.EnvKeyFacebookClientSecret] = osFacebookClientSecret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyLinkedInClientID]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID
|
||||||
|
}
|
||||||
|
if osFacebookClientID != "" && envData[constants.EnvKeyLinkedInClientID] != osFacebookClientID {
|
||||||
|
envData[constants.EnvKeyLinkedInClientID] = osLinkedInClientID
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyLinkedInClientSecret]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret
|
||||||
|
}
|
||||||
|
if osFacebookClientSecret != "" && envData[constants.EnvKeyLinkedInClientSecret] != osFacebookClientSecret {
|
||||||
|
envData[constants.EnvKeyLinkedInClientSecret] = osLinkedInClientSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyAppleClientID]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyAppleClientID] = osAppleClientID
|
||||||
|
}
|
||||||
|
if osFacebookClientID != "" && envData[constants.EnvKeyAppleClientID] != osFacebookClientID {
|
||||||
|
envData[constants.EnvKeyAppleClientID] = osAppleClientID
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := envData[constants.EnvKeyAppleClientSecret]; !ok || val == "" {
|
||||||
|
envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret
|
||||||
|
}
|
||||||
|
if osFacebookClientSecret != "" && envData[constants.EnvKeyAppleClientSecret] != osFacebookClientSecret {
|
||||||
|
envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret
|
||||||
|
}
|
||||||
|
|
||||||
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
|
||||||
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
|
||||||
}
|
}
|
||||||
@@ -444,6 +477,19 @@ func InitAllEnv() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := envData[constants.EnvKeyDisableStrongPassword]; !ok {
|
||||||
|
envData[constants.EnvKeyDisableStrongPassword] = osDisableStrongPassword == "true"
|
||||||
|
}
|
||||||
|
if osDisableStrongPassword != "" {
|
||||||
|
boolValue, err := strconv.ParseBool(osDisableStrongPassword)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if boolValue != envData[constants.EnvKeyDisableStrongPassword].(bool) {
|
||||||
|
envData[constants.EnvKeyDisableStrongPassword] = boolValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// no need to add nil check as its already done above
|
// no need to add nil check as its already done above
|
||||||
if envData[constants.EnvKeySmtpHost] == "" || envData[constants.EnvKeySmtpUsername] == "" || envData[constants.EnvKeySmtpPassword] == "" || envData[constants.EnvKeySenderEmail] == "" && envData[constants.EnvKeySmtpPort] == "" {
|
if envData[constants.EnvKeySmtpHost] == "" || envData[constants.EnvKeySmtpUsername] == "" || envData[constants.EnvKeySmtpPassword] == "" || envData[constants.EnvKeySenderEmail] == "" && envData[constants.EnvKeySmtpPort] == "" {
|
||||||
envData[constants.EnvKeyDisableEmailVerification] = true
|
envData[constants.EnvKeyDisableEmailVerification] = true
|
||||||
|
2
server/env/persist_env.go
vendored
2
server/env/persist_env.go
vendored
@@ -198,7 +198,7 @@ func PersistEnv() error {
|
|||||||
envValue := strings.TrimSpace(os.Getenv(key))
|
envValue := strings.TrimSpace(os.Getenv(key))
|
||||||
if envValue != "" {
|
if envValue != "" {
|
||||||
switch key {
|
switch key {
|
||||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv:
|
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword:
|
||||||
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
||||||
if value.(bool) != envValueBool {
|
if value.(bool) != envValueBool {
|
||||||
storeData[key] = envValueBool
|
storeData[key] = envValueBool
|
||||||
|
@@ -57,6 +57,8 @@ type ComplexityRoot struct {
|
|||||||
AdminSecret func(childComplexity int) int
|
AdminSecret func(childComplexity int) int
|
||||||
AllowedOrigins func(childComplexity int) int
|
AllowedOrigins func(childComplexity int) int
|
||||||
AppURL func(childComplexity int) int
|
AppURL func(childComplexity int) int
|
||||||
|
AppleClientID func(childComplexity int) int
|
||||||
|
AppleClientSecret func(childComplexity int) int
|
||||||
ClientID func(childComplexity int) int
|
ClientID func(childComplexity int) int
|
||||||
ClientSecret func(childComplexity int) int
|
ClientSecret func(childComplexity int) int
|
||||||
CustomAccessTokenScript func(childComplexity int) int
|
CustomAccessTokenScript func(childComplexity int) int
|
||||||
@@ -74,6 +76,7 @@ type ComplexityRoot struct {
|
|||||||
DisableMagicLinkLogin func(childComplexity int) int
|
DisableMagicLinkLogin func(childComplexity int) int
|
||||||
DisableRedisForEnv func(childComplexity int) int
|
DisableRedisForEnv func(childComplexity int) int
|
||||||
DisableSignUp func(childComplexity int) int
|
DisableSignUp func(childComplexity int) int
|
||||||
|
DisableStrongPassword func(childComplexity int) int
|
||||||
FacebookClientID func(childComplexity int) int
|
FacebookClientID func(childComplexity int) int
|
||||||
FacebookClientSecret func(childComplexity int) int
|
FacebookClientSecret func(childComplexity int) int
|
||||||
GithubClientID func(childComplexity int) int
|
GithubClientID func(childComplexity int) int
|
||||||
@@ -85,6 +88,8 @@ type ComplexityRoot struct {
|
|||||||
JwtRoleClaim func(childComplexity int) int
|
JwtRoleClaim func(childComplexity int) int
|
||||||
JwtSecret func(childComplexity int) int
|
JwtSecret func(childComplexity int) int
|
||||||
JwtType func(childComplexity int) int
|
JwtType func(childComplexity int) int
|
||||||
|
LinkedinClientID func(childComplexity int) int
|
||||||
|
LinkedinClientSecret func(childComplexity int) int
|
||||||
OrganizationLogo func(childComplexity int) int
|
OrganizationLogo func(childComplexity int) int
|
||||||
OrganizationName func(childComplexity int) int
|
OrganizationName func(childComplexity int) int
|
||||||
ProtectedRoles func(childComplexity int) int
|
ProtectedRoles func(childComplexity int) int
|
||||||
@@ -111,13 +116,16 @@ type ComplexityRoot struct {
|
|||||||
|
|
||||||
Meta struct {
|
Meta struct {
|
||||||
ClientID func(childComplexity int) int
|
ClientID func(childComplexity int) int
|
||||||
|
IsAppleLoginEnabled func(childComplexity int) int
|
||||||
IsBasicAuthenticationEnabled func(childComplexity int) int
|
IsBasicAuthenticationEnabled func(childComplexity int) int
|
||||||
IsEmailVerificationEnabled func(childComplexity int) int
|
IsEmailVerificationEnabled func(childComplexity int) int
|
||||||
IsFacebookLoginEnabled func(childComplexity int) int
|
IsFacebookLoginEnabled func(childComplexity int) int
|
||||||
IsGithubLoginEnabled func(childComplexity int) int
|
IsGithubLoginEnabled func(childComplexity int) int
|
||||||
IsGoogleLoginEnabled func(childComplexity int) int
|
IsGoogleLoginEnabled func(childComplexity int) int
|
||||||
|
IsLinkedinLoginEnabled func(childComplexity int) int
|
||||||
IsMagicLinkLoginEnabled func(childComplexity int) int
|
IsMagicLinkLoginEnabled func(childComplexity int) int
|
||||||
IsSignUpEnabled func(childComplexity int) int
|
IsSignUpEnabled func(childComplexity int) int
|
||||||
|
IsStrongPasswordEnabled func(childComplexity int) int
|
||||||
Version func(childComplexity int) int
|
Version func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,6 +340,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Env.AppURL(childComplexity), true
|
return e.complexity.Env.AppURL(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.APPLE_CLIENT_ID":
|
||||||
|
if e.complexity.Env.AppleClientID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.AppleClientID(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.APPLE_CLIENT_SECRET":
|
||||||
|
if e.complexity.Env.AppleClientSecret == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.AppleClientSecret(childComplexity), true
|
||||||
|
|
||||||
case "Env.CLIENT_ID":
|
case "Env.CLIENT_ID":
|
||||||
if e.complexity.Env.ClientID == nil {
|
if e.complexity.Env.ClientID == nil {
|
||||||
break
|
break
|
||||||
@@ -451,6 +473,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Env.DisableSignUp(childComplexity), true
|
return e.complexity.Env.DisableSignUp(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.DISABLE_STRONG_PASSWORD":
|
||||||
|
if e.complexity.Env.DisableStrongPassword == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.DisableStrongPassword(childComplexity), true
|
||||||
|
|
||||||
case "Env.FACEBOOK_CLIENT_ID":
|
case "Env.FACEBOOK_CLIENT_ID":
|
||||||
if e.complexity.Env.FacebookClientID == nil {
|
if e.complexity.Env.FacebookClientID == nil {
|
||||||
break
|
break
|
||||||
@@ -528,6 +557,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Env.JwtType(childComplexity), true
|
return e.complexity.Env.JwtType(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.LINKEDIN_CLIENT_ID":
|
||||||
|
if e.complexity.Env.LinkedinClientID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.LinkedinClientID(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.LINKEDIN_CLIENT_SECRET":
|
||||||
|
if e.complexity.Env.LinkedinClientSecret == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.LinkedinClientSecret(childComplexity), true
|
||||||
|
|
||||||
case "Env.ORGANIZATION_LOGO":
|
case "Env.ORGANIZATION_LOGO":
|
||||||
if e.complexity.Env.OrganizationLogo == nil {
|
if e.complexity.Env.OrganizationLogo == nil {
|
||||||
break
|
break
|
||||||
@@ -647,6 +690,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Meta.ClientID(childComplexity), true
|
return e.complexity.Meta.ClientID(childComplexity), true
|
||||||
|
|
||||||
|
case "Meta.is_apple_login_enabled":
|
||||||
|
if e.complexity.Meta.IsAppleLoginEnabled == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Meta.IsAppleLoginEnabled(childComplexity), true
|
||||||
|
|
||||||
case "Meta.is_basic_authentication_enabled":
|
case "Meta.is_basic_authentication_enabled":
|
||||||
if e.complexity.Meta.IsBasicAuthenticationEnabled == nil {
|
if e.complexity.Meta.IsBasicAuthenticationEnabled == nil {
|
||||||
break
|
break
|
||||||
@@ -682,6 +732,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Meta.IsGoogleLoginEnabled(childComplexity), true
|
return e.complexity.Meta.IsGoogleLoginEnabled(childComplexity), true
|
||||||
|
|
||||||
|
case "Meta.is_linkedin_login_enabled":
|
||||||
|
if e.complexity.Meta.IsLinkedinLoginEnabled == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Meta.IsLinkedinLoginEnabled(childComplexity), true
|
||||||
|
|
||||||
case "Meta.is_magic_link_login_enabled":
|
case "Meta.is_magic_link_login_enabled":
|
||||||
if e.complexity.Meta.IsMagicLinkLoginEnabled == nil {
|
if e.complexity.Meta.IsMagicLinkLoginEnabled == nil {
|
||||||
break
|
break
|
||||||
@@ -696,6 +753,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Meta.IsSignUpEnabled(childComplexity), true
|
return e.complexity.Meta.IsSignUpEnabled(childComplexity), true
|
||||||
|
|
||||||
|
case "Meta.is_strong_password_enabled":
|
||||||
|
if e.complexity.Meta.IsStrongPasswordEnabled == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Meta.IsStrongPasswordEnabled(childComplexity), true
|
||||||
|
|
||||||
case "Meta.version":
|
case "Meta.version":
|
||||||
if e.complexity.Meta.Version == nil {
|
if e.complexity.Meta.Version == nil {
|
||||||
break
|
break
|
||||||
@@ -1352,10 +1416,13 @@ type Meta {
|
|||||||
is_google_login_enabled: Boolean!
|
is_google_login_enabled: Boolean!
|
||||||
is_facebook_login_enabled: Boolean!
|
is_facebook_login_enabled: Boolean!
|
||||||
is_github_login_enabled: Boolean!
|
is_github_login_enabled: Boolean!
|
||||||
|
is_linkedin_login_enabled: Boolean!
|
||||||
|
is_apple_login_enabled: Boolean!
|
||||||
is_email_verification_enabled: Boolean!
|
is_email_verification_enabled: Boolean!
|
||||||
is_basic_authentication_enabled: Boolean!
|
is_basic_authentication_enabled: Boolean!
|
||||||
is_magic_link_login_enabled: Boolean!
|
is_magic_link_login_enabled: Boolean!
|
||||||
is_sign_up_enabled: Boolean!
|
is_sign_up_enabled: Boolean!
|
||||||
|
is_strong_password_enabled: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type User {
|
type User {
|
||||||
@@ -1452,6 +1519,7 @@ type Env {
|
|||||||
DISABLE_LOGIN_PAGE: Boolean!
|
DISABLE_LOGIN_PAGE: Boolean!
|
||||||
DISABLE_SIGN_UP: Boolean!
|
DISABLE_SIGN_UP: Boolean!
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean!
|
DISABLE_REDIS_FOR_ENV: Boolean!
|
||||||
|
DISABLE_STRONG_PASSWORD: Boolean!
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
@@ -1462,6 +1530,10 @@ type Env {
|
|||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
|
LINKEDIN_CLIENT_ID: String
|
||||||
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
|
APPLE_CLIENT_ID: String
|
||||||
|
APPLE_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
}
|
}
|
||||||
@@ -1499,6 +1571,7 @@ input UpdateEnvInput {
|
|||||||
DISABLE_LOGIN_PAGE: Boolean
|
DISABLE_LOGIN_PAGE: Boolean
|
||||||
DISABLE_SIGN_UP: Boolean
|
DISABLE_SIGN_UP: Boolean
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean
|
DISABLE_REDIS_FOR_ENV: Boolean
|
||||||
|
DISABLE_STRONG_PASSWORD: Boolean
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
@@ -1509,6 +1582,10 @@ input UpdateEnvInput {
|
|||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
|
LINKEDIN_CLIENT_ID: String
|
||||||
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
|
APPLE_CLIENT_ID: String
|
||||||
|
APPLE_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
}
|
}
|
||||||
@@ -3282,6 +3359,41 @@ func (ec *executionContext) _Env_DISABLE_REDIS_FOR_ENV(ctx context.Context, fiel
|
|||||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_DISABLE_STRONG_PASSWORD(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.DisableStrongPassword, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Env_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Env_ROLES(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -3602,6 +3714,134 @@ func (ec *executionContext) _Env_FACEBOOK_CLIENT_SECRET(ctx context.Context, fie
|
|||||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_LINKEDIN_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.LinkedinClientID, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_LINKEDIN_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.LinkedinClientSecret, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_APPLE_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.AppleClientID, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_APPLE_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.AppleClientSecret, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Env_ORGANIZATION_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Env_ORGANIZATION_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -4007,6 +4247,76 @@ func (ec *executionContext) _Meta_is_github_login_enabled(ctx context.Context, f
|
|||||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Meta_is_linkedin_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Meta",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.IsLinkedinLoginEnabled, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Meta_is_apple_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Meta",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.IsAppleLoginEnabled, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Meta_is_email_verification_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Meta_is_email_verification_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -4147,6 +4457,41 @@ func (ec *executionContext) _Meta_is_sign_up_enabled(ctx context.Context, field
|
|||||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Meta_is_strong_password_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Meta",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.IsStrongPasswordEnabled, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_signup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -8483,6 +8828,14 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
|
case "DISABLE_STRONG_PASSWORD":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_STRONG_PASSWORD"))
|
||||||
|
it.DisableStrongPassword, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
case "ROLES":
|
case "ROLES":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -8563,6 +8916,38 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
|
case "LINKEDIN_CLIENT_ID":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("LINKEDIN_CLIENT_ID"))
|
||||||
|
it.LinkedinClientID, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "LINKEDIN_CLIENT_SECRET":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("LINKEDIN_CLIENT_SECRET"))
|
||||||
|
it.LinkedinClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "APPLE_CLIENT_ID":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("APPLE_CLIENT_ID"))
|
||||||
|
it.AppleClientID, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
case "APPLE_CLIENT_SECRET":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("APPLE_CLIENT_SECRET"))
|
||||||
|
it.AppleClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
case "ORGANIZATION_NAME":
|
case "ORGANIZATION_NAME":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -9011,6 +9396,11 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "DISABLE_STRONG_PASSWORD":
|
||||||
|
out.Values[i] = ec._Env_DISABLE_STRONG_PASSWORD(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
case "ROLES":
|
case "ROLES":
|
||||||
out.Values[i] = ec._Env_ROLES(ctx, field, obj)
|
out.Values[i] = ec._Env_ROLES(ctx, field, obj)
|
||||||
case "PROTECTED_ROLES":
|
case "PROTECTED_ROLES":
|
||||||
@@ -9031,6 +9421,14 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
out.Values[i] = ec._Env_FACEBOOK_CLIENT_ID(ctx, field, obj)
|
out.Values[i] = ec._Env_FACEBOOK_CLIENT_ID(ctx, field, obj)
|
||||||
case "FACEBOOK_CLIENT_SECRET":
|
case "FACEBOOK_CLIENT_SECRET":
|
||||||
out.Values[i] = ec._Env_FACEBOOK_CLIENT_SECRET(ctx, field, obj)
|
out.Values[i] = ec._Env_FACEBOOK_CLIENT_SECRET(ctx, field, obj)
|
||||||
|
case "LINKEDIN_CLIENT_ID":
|
||||||
|
out.Values[i] = ec._Env_LINKEDIN_CLIENT_ID(ctx, field, obj)
|
||||||
|
case "LINKEDIN_CLIENT_SECRET":
|
||||||
|
out.Values[i] = ec._Env_LINKEDIN_CLIENT_SECRET(ctx, field, obj)
|
||||||
|
case "APPLE_CLIENT_ID":
|
||||||
|
out.Values[i] = ec._Env_APPLE_CLIENT_ID(ctx, field, obj)
|
||||||
|
case "APPLE_CLIENT_SECRET":
|
||||||
|
out.Values[i] = ec._Env_APPLE_CLIENT_SECRET(ctx, field, obj)
|
||||||
case "ORGANIZATION_NAME":
|
case "ORGANIZATION_NAME":
|
||||||
out.Values[i] = ec._Env_ORGANIZATION_NAME(ctx, field, obj)
|
out.Values[i] = ec._Env_ORGANIZATION_NAME(ctx, field, obj)
|
||||||
case "ORGANIZATION_LOGO":
|
case "ORGANIZATION_LOGO":
|
||||||
@@ -9142,6 +9540,16 @@ func (ec *executionContext) _Meta(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "is_linkedin_login_enabled":
|
||||||
|
out.Values[i] = ec._Meta_is_linkedin_login_enabled(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
case "is_apple_login_enabled":
|
||||||
|
out.Values[i] = ec._Meta_is_apple_login_enabled(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
case "is_email_verification_enabled":
|
case "is_email_verification_enabled":
|
||||||
out.Values[i] = ec._Meta_is_email_verification_enabled(ctx, field, obj)
|
out.Values[i] = ec._Meta_is_email_verification_enabled(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
@@ -9162,6 +9570,11 @@ func (ec *executionContext) _Meta(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "is_strong_password_enabled":
|
||||||
|
out.Values[i] = ec._Meta_is_strong_password_enabled(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,7 @@ type Env struct {
|
|||||||
DisableLoginPage bool `json:"DISABLE_LOGIN_PAGE"`
|
DisableLoginPage bool `json:"DISABLE_LOGIN_PAGE"`
|
||||||
DisableSignUp bool `json:"DISABLE_SIGN_UP"`
|
DisableSignUp bool `json:"DISABLE_SIGN_UP"`
|
||||||
DisableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"`
|
DisableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"`
|
||||||
|
DisableStrongPassword bool `json:"DISABLE_STRONG_PASSWORD"`
|
||||||
Roles []string `json:"ROLES"`
|
Roles []string `json:"ROLES"`
|
||||||
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
||||||
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
||||||
@@ -65,6 +66,10 @@ type Env struct {
|
|||||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
||||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
||||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
||||||
|
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID"`
|
||||||
|
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
|
||||||
|
AppleClientID *string `json:"APPLE_CLIENT_ID"`
|
||||||
|
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||||
}
|
}
|
||||||
@@ -116,10 +121,13 @@ type Meta struct {
|
|||||||
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
|
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
|
||||||
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
|
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
|
||||||
IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
|
IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
|
||||||
|
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
|
||||||
|
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
||||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||||
IsSignUpEnabled bool `json:"is_sign_up_enabled"`
|
IsSignUpEnabled bool `json:"is_sign_up_enabled"`
|
||||||
|
IsStrongPasswordEnabled bool `json:"is_strong_password_enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OAuthRevokeInput struct {
|
type OAuthRevokeInput struct {
|
||||||
@@ -206,6 +214,7 @@ type UpdateEnvInput struct {
|
|||||||
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"`
|
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE"`
|
||||||
DisableSignUp *bool `json:"DISABLE_SIGN_UP"`
|
DisableSignUp *bool `json:"DISABLE_SIGN_UP"`
|
||||||
DisableRedisForEnv *bool `json:"DISABLE_REDIS_FOR_ENV"`
|
DisableRedisForEnv *bool `json:"DISABLE_REDIS_FOR_ENV"`
|
||||||
|
DisableStrongPassword *bool `json:"DISABLE_STRONG_PASSWORD"`
|
||||||
Roles []string `json:"ROLES"`
|
Roles []string `json:"ROLES"`
|
||||||
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
ProtectedRoles []string `json:"PROTECTED_ROLES"`
|
||||||
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
DefaultRoles []string `json:"DEFAULT_ROLES"`
|
||||||
@@ -216,6 +225,10 @@ type UpdateEnvInput struct {
|
|||||||
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
GithubClientSecret *string `json:"GITHUB_CLIENT_SECRET"`
|
||||||
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
FacebookClientID *string `json:"FACEBOOK_CLIENT_ID"`
|
||||||
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
FacebookClientSecret *string `json:"FACEBOOK_CLIENT_SECRET"`
|
||||||
|
LinkedinClientID *string `json:"LINKEDIN_CLIENT_ID"`
|
||||||
|
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
|
||||||
|
AppleClientID *string `json:"APPLE_CLIENT_ID"`
|
||||||
|
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
|
||||||
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
OrganizationName *string `json:"ORGANIZATION_NAME"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
|
||||||
}
|
}
|
||||||
|
@@ -18,10 +18,13 @@ type Meta {
|
|||||||
is_google_login_enabled: Boolean!
|
is_google_login_enabled: Boolean!
|
||||||
is_facebook_login_enabled: Boolean!
|
is_facebook_login_enabled: Boolean!
|
||||||
is_github_login_enabled: Boolean!
|
is_github_login_enabled: Boolean!
|
||||||
|
is_linkedin_login_enabled: Boolean!
|
||||||
|
is_apple_login_enabled: Boolean!
|
||||||
is_email_verification_enabled: Boolean!
|
is_email_verification_enabled: Boolean!
|
||||||
is_basic_authentication_enabled: Boolean!
|
is_basic_authentication_enabled: Boolean!
|
||||||
is_magic_link_login_enabled: Boolean!
|
is_magic_link_login_enabled: Boolean!
|
||||||
is_sign_up_enabled: Boolean!
|
is_sign_up_enabled: Boolean!
|
||||||
|
is_strong_password_enabled: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type User {
|
type User {
|
||||||
@@ -118,6 +121,7 @@ type Env {
|
|||||||
DISABLE_LOGIN_PAGE: Boolean!
|
DISABLE_LOGIN_PAGE: Boolean!
|
||||||
DISABLE_SIGN_UP: Boolean!
|
DISABLE_SIGN_UP: Boolean!
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean!
|
DISABLE_REDIS_FOR_ENV: Boolean!
|
||||||
|
DISABLE_STRONG_PASSWORD: Boolean!
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
@@ -128,6 +132,10 @@ type Env {
|
|||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
|
LINKEDIN_CLIENT_ID: String
|
||||||
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
|
APPLE_CLIENT_ID: String
|
||||||
|
APPLE_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
}
|
}
|
||||||
@@ -165,6 +173,7 @@ input UpdateEnvInput {
|
|||||||
DISABLE_LOGIN_PAGE: Boolean
|
DISABLE_LOGIN_PAGE: Boolean
|
||||||
DISABLE_SIGN_UP: Boolean
|
DISABLE_SIGN_UP: Boolean
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean
|
DISABLE_REDIS_FOR_ENV: Boolean
|
||||||
|
DISABLE_STRONG_PASSWORD: Boolean
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
@@ -175,6 +184,10 @@ input UpdateEnvInput {
|
|||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
|
LINKEDIN_CLIENT_ID: String
|
||||||
|
LINKEDIN_CLIENT_SECRET: String
|
||||||
|
APPLE_CLIENT_ID: String
|
||||||
|
APPLE_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
}
|
}
|
||||||
|
@@ -218,16 +218,18 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionKey := user.ID
|
||||||
|
if claims.LoginMethod != "" {
|
||||||
|
sessionKey = claims.LoginMethod + ":" + user.ID
|
||||||
|
}
|
||||||
|
|
||||||
// if user is logged in
|
// if user is logged in
|
||||||
// based on the response type, generate the response
|
// based on the response type code, generate the response
|
||||||
if isResponseTypeCode {
|
if isResponseTypeCode {
|
||||||
// rollover the session for security
|
// rollover the session for security
|
||||||
err = memorystore.Provider.RemoveState(sessionToken)
|
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to remove state: ", err)
|
|
||||||
}
|
|
||||||
nonce := uuid.New().String()
|
nonce := uuid.New().String()
|
||||||
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope)
|
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isQuery {
|
if isQuery {
|
||||||
gc.Redirect(http.StatusFound, loginURL)
|
gc.Redirect(http.StatusFound, loginURL)
|
||||||
@@ -246,7 +248,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.SetState(newSessionToken, newSessionTokenData.Nonce+"@"+user.ID)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken)
|
||||||
cookie.SetSession(gc, newSessionToken)
|
cookie.SetSession(gc, newSessionToken)
|
||||||
code := uuid.New().String()
|
code := uuid.New().String()
|
||||||
memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken)
|
memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken)
|
||||||
@@ -265,7 +267,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
if isResponseTypeToken {
|
if isResponseTypeToken {
|
||||||
// rollover the session for security
|
// rollover the session for security
|
||||||
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope)
|
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isQuery {
|
if isQuery {
|
||||||
gc.Redirect(http.StatusFound, loginURL)
|
gc.Redirect(http.StatusFound, loginURL)
|
||||||
@@ -283,9 +285,10 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
memorystore.Provider.RemoveState(sessionToken)
|
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
|
||||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
@@ -308,7 +311,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
|||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res["refresh_token"] = authToken.RefreshToken.Token
|
res["refresh_token"] = authToken.RefreshToken.Token
|
||||||
params += "&refresh_token=" + authToken.RefreshToken.Token
|
params += "&refresh_token=" + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isQuery {
|
if isQuery {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler to logout user
|
// Handler to logout user
|
||||||
@@ -35,12 +37,17 @@ func LogoutHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fingerPrint := string(decryptedFingerPrint)
|
var sessionData token.SessionData
|
||||||
|
err = json.Unmarshal([]byte(decryptedFingerPrint), &sessionData)
|
||||||
err = memorystore.Provider.RemoveState(fingerPrint)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to remove state: ", err)
|
log.Debug("Failed to decrypt fingerprint: ", err)
|
||||||
|
gc.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memorystore.Provider.DeleteUserSession(sessionData.Subject, sessionData.Nonce)
|
||||||
cookie.DeleteSession(gc)
|
cookie.DeleteSession(gc)
|
||||||
|
|
||||||
if redirectURL != "" {
|
if redirectURL != "" {
|
||||||
|
@@ -2,6 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -36,7 +37,6 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
log.Debug("Invalid oauth state: ", state)
|
log.Debug("Invalid oauth state: ", state)
|
||||||
c.JSON(400, gin.H{"error": "invalid oauth state"})
|
c.JSON(400, gin.H{"error": "invalid oauth state"})
|
||||||
}
|
}
|
||||||
memorystore.Provider.GetState(state)
|
|
||||||
// contains random token, redirect url, role
|
// contains random token, redirect url, role
|
||||||
sessionSplit := strings.Split(state, "___")
|
sessionSplit := strings.Split(state, "___")
|
||||||
|
|
||||||
@@ -46,6 +46,9 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove state from store
|
||||||
|
go memorystore.Provider.RemoveState(state)
|
||||||
|
|
||||||
stateValue := sessionSplit[0]
|
stateValue := sessionSplit[0]
|
||||||
redirectURL := sessionSplit[1]
|
redirectURL := sessionSplit[1]
|
||||||
inputRoles := strings.Split(sessionSplit[2], ",")
|
inputRoles := strings.Split(sessionSplit[2], ",")
|
||||||
@@ -54,12 +57,16 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
user := models.User{}
|
user := models.User{}
|
||||||
code := c.Request.FormValue("code")
|
code := c.Request.FormValue("code")
|
||||||
switch provider {
|
switch provider {
|
||||||
case constants.SignupMethodGoogle:
|
case constants.AuthRecipeMethodGoogle:
|
||||||
user, err = processGoogleUserInfo(code)
|
user, err = processGoogleUserInfo(code)
|
||||||
case constants.SignupMethodGithub:
|
case constants.AuthRecipeMethodGithub:
|
||||||
user, err = processGithubUserInfo(code)
|
user, err = processGithubUserInfo(code)
|
||||||
case constants.SignupMethodFacebook:
|
case constants.AuthRecipeMethodFacebook:
|
||||||
user, err = processFacebookUserInfo(code)
|
user, err = processFacebookUserInfo(code)
|
||||||
|
case constants.AuthRecipeMethodLinkedIn:
|
||||||
|
user, err = processLinkedInUserInfo(code)
|
||||||
|
case constants.AuthRecipeMethodApple:
|
||||||
|
user, err = processAppleUserInfo(code)
|
||||||
default:
|
default:
|
||||||
log.Info("Invalid oauth provider")
|
log.Info("Invalid oauth provider")
|
||||||
err = fmt.Errorf(`invalid oauth provider`)
|
err = fmt.Errorf(`invalid oauth provider`)
|
||||||
@@ -115,9 +122,11 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
user.EmailVerifiedAt = &now
|
user.EmailVerifiedAt = &now
|
||||||
user, _ = db.Provider.AddUser(user)
|
user, _ = db.Provider.AddUser(user)
|
||||||
} else {
|
} else {
|
||||||
|
user = existingUser
|
||||||
if user.RevokedTimestamp != nil {
|
if user.RevokedTimestamp != nil {
|
||||||
log.Debug("User access revoked at: ", user.RevokedTimestamp)
|
log.Debug("User access revoked at: ", user.RevokedTimestamp)
|
||||||
c.JSON(400, gin.H{"error": "user access has been revoked"})
|
c.JSON(400, gin.H{"error": "user access has been revoked"})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// user exists in db, check if method was google
|
// user exists in db, check if method was google
|
||||||
@@ -126,7 +135,6 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
if !strings.Contains(signupMethod, provider) {
|
if !strings.Contains(signupMethod, provider) {
|
||||||
signupMethod = signupMethod + "," + provider
|
signupMethod = signupMethod + "," + provider
|
||||||
}
|
}
|
||||||
user = existingUser
|
|
||||||
user.SignupMethods = signupMethod
|
user.SignupMethods = signupMethod
|
||||||
|
|
||||||
if user.EmailVerifiedAt == nil {
|
if user.EmailVerifiedAt == nil {
|
||||||
@@ -184,7 +192,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authToken, err := token.CreateAuthToken(c, user, inputRoles, scopes)
|
authToken, err := token.CreateAuthToken(c, user, inputRoles, scopes, provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to create auth token: ", err)
|
log.Debug("Failed to create auth token: ", err)
|
||||||
c.JSON(500, gin.H{"error": err.Error()})
|
c.JSON(500, gin.H{"error": err.Error()})
|
||||||
@@ -197,13 +205,14 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token
|
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token
|
||||||
|
|
||||||
|
sessionKey := provider + ":" + user.ID
|
||||||
cookie.SetSession(c, authToken.FingerPrintHash)
|
cookie.SetSession(c, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
@@ -214,10 +223,10 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
|||||||
if strings.Contains(redirectURL, "?") {
|
if strings.Contains(redirectURL, "?") {
|
||||||
redirectURL = redirectURL + "&" + params
|
redirectURL = redirectURL + "&" + params
|
||||||
} else {
|
} else {
|
||||||
redirectURL = redirectURL + "?" + params
|
redirectURL = redirectURL + "?" + strings.TrimPrefix(params, "&")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Redirect(http.StatusTemporaryRedirect, redirectURL)
|
c.Redirect(http.StatusFound, redirectURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +265,7 @@ func processGoogleUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
func processGithubUserInfo(code string) (models.User, error) {
|
func processGithubUserInfo(code string) (models.User, error) {
|
||||||
user := models.User{}
|
user := models.User{}
|
||||||
token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code)
|
oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to exchange code for token: ", err)
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
return user, fmt.Errorf("invalid github exchange code: %s", err.Error())
|
return user, fmt.Errorf("invalid github exchange code: %s", err.Error())
|
||||||
@@ -268,7 +277,7 @@ func processGithubUserInfo(code string) (models.User, error) {
|
|||||||
return user, fmt.Errorf("error creating github user info request: %s", err.Error())
|
return user, fmt.Errorf("error creating github user info request: %s", err.Error())
|
||||||
}
|
}
|
||||||
req.Header = http.Header{
|
req.Header = http.Header{
|
||||||
"Authorization": []string{fmt.Sprintf("token %s", token.AccessToken)},
|
"Authorization": []string{fmt.Sprintf("token %s", oauth2Token.AccessToken)},
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.Do(req)
|
response, err := client.Do(req)
|
||||||
@@ -283,6 +292,10 @@ func processGithubUserInfo(code string) (models.User, error) {
|
|||||||
log.Debug("Failed to read github user info response body: ", err)
|
log.Debug("Failed to read github user info response body: ", err)
|
||||||
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read github response body: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
log.Debug("Failed to request github user info: ", string(body))
|
||||||
|
return user, fmt.Errorf("failed to request github user info: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
userRawData := make(map[string]string)
|
userRawData := make(map[string]string)
|
||||||
json.Unmarshal(body, &userRawData)
|
json.Unmarshal(body, &userRawData)
|
||||||
@@ -311,13 +324,13 @@ func processGithubUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
func processFacebookUserInfo(code string) (models.User, error) {
|
func processFacebookUserInfo(code string) (models.User, error) {
|
||||||
user := models.User{}
|
user := models.User{}
|
||||||
token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code)
|
oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Invalid facebook exchange code: ", err)
|
log.Debug("Invalid facebook exchange code: ", err)
|
||||||
return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error())
|
return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error())
|
||||||
}
|
}
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+token.AccessToken, nil)
|
req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+oauth2Token.AccessToken, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error creating facebook user info request: ", err)
|
log.Debug("Error creating facebook user info request: ", err)
|
||||||
return user, fmt.Errorf("error creating facebook user info request: %s", err.Error())
|
return user, fmt.Errorf("error creating facebook user info request: %s", err.Error())
|
||||||
@@ -335,7 +348,10 @@ func processFacebookUserInfo(code string) (models.User, error) {
|
|||||||
log.Debug("Failed to read facebook response: ", err)
|
log.Debug("Failed to read facebook response: ", err)
|
||||||
return user, fmt.Errorf("failed to read facebook response body: %s", err.Error())
|
return user, fmt.Errorf("failed to read facebook response body: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
log.Debug("Failed to request facebook user info: ", string(body))
|
||||||
|
return user, fmt.Errorf("failed to request facebook user info: %s", string(body))
|
||||||
|
}
|
||||||
userRawData := make(map[string]interface{})
|
userRawData := make(map[string]interface{})
|
||||||
json.Unmarshal(body, &userRawData)
|
json.Unmarshal(body, &userRawData)
|
||||||
|
|
||||||
@@ -356,3 +372,138 @@ func processFacebookUserInfo(code string) (models.User, error) {
|
|||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processLinkedInUserInfo(code string) (models.User, error) {
|
||||||
|
user := models.User{}
|
||||||
|
oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(oauth2.NoContext, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
|
return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
client := http.Client{}
|
||||||
|
req, err := http.NewRequest("GET", constants.LinkedInUserInfoURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create linkedin user info request: ", err)
|
||||||
|
return user, fmt.Errorf("error creating linkedin user info request: %s", err.Error())
|
||||||
|
}
|
||||||
|
req.Header = http.Header{
|
||||||
|
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to request linkedin user info: ", err)
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer response.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to read linkedin user info response body: ", err)
|
||||||
|
return user, fmt.Errorf("failed to read linkedin response body: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
log.Debug("Failed to request linkedin user info: ", string(body))
|
||||||
|
return user, fmt.Errorf("failed to request linkedin user info: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
userRawData := make(map[string]interface{})
|
||||||
|
json.Unmarshal(body, &userRawData)
|
||||||
|
|
||||||
|
req, err = http.NewRequest("GET", constants.LinkedInEmailURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create linkedin email info request: ", err)
|
||||||
|
return user, fmt.Errorf("error creating linkedin user info request: %s", err.Error())
|
||||||
|
}
|
||||||
|
req.Header = http.Header{
|
||||||
|
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to request linkedin email info: ", err)
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer response.Body.Close()
|
||||||
|
body, err = ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to read linkedin email info response body: ", err)
|
||||||
|
return user, fmt.Errorf("failed to read linkedin email response body: %s", err.Error())
|
||||||
|
}
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
log.Debug("Failed to request linkedin user info: ", string(body))
|
||||||
|
return user, fmt.Errorf("failed to request linkedin user info: %s", string(body))
|
||||||
|
}
|
||||||
|
emailRawData := make(map[string]interface{})
|
||||||
|
json.Unmarshal(body, &emailRawData)
|
||||||
|
|
||||||
|
firstName := userRawData["localizedFirstName"].(string)
|
||||||
|
lastName := userRawData["localizedLastName"].(string)
|
||||||
|
profilePicture := userRawData["profilePicture"].(map[string]interface{})["displayImage~"].(map[string]interface{})["elements"].([]interface{})[0].(map[string]interface{})["identifiers"].([]interface{})[0].(map[string]interface{})["identifier"].(string)
|
||||||
|
emailAddress := emailRawData["elements"].([]interface{})[0].(map[string]interface{})["handle~"].(map[string]interface{})["emailAddress"].(string)
|
||||||
|
|
||||||
|
user = models.User{
|
||||||
|
GivenName: &firstName,
|
||||||
|
FamilyName: &lastName,
|
||||||
|
Picture: &profilePicture,
|
||||||
|
Email: emailAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processAppleUserInfo(code string) (models.User, error) {
|
||||||
|
user := models.User{}
|
||||||
|
oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(oauth2.NoContext, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
|
return user, fmt.Errorf("invalid apple exchange code: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the ID Token from OAuth2 token.
|
||||||
|
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||||
|
if !ok {
|
||||||
|
log.Debug("Failed to extract ID Token from OAuth2 token")
|
||||||
|
return user, fmt.Errorf("unable to extract id_token")
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenSplit := strings.Split(rawIDToken, ".")
|
||||||
|
claimsData := tokenSplit[1]
|
||||||
|
decodedClaimsData, err := base64.RawURLEncoding.DecodeString(claimsData)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Failed to decrypt claims %s: %s", claimsData, err.Error())
|
||||||
|
return user, fmt.Errorf("failed to decrypt claims data: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := make(map[string]interface{})
|
||||||
|
err = json.Unmarshal(decodedClaimsData, &claims)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to unmarshal claims data: ", err)
|
||||||
|
return user, fmt.Errorf("failed to unmarshal claims data: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := claims["email"]; !ok {
|
||||||
|
log.Debug("Failed to extract email from claims.")
|
||||||
|
return user, fmt.Errorf("unable to extract email, please check the scopes enabled for your app. It needs `email`, `name` scopes")
|
||||||
|
} else {
|
||||||
|
user.Email = val.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := claims["name"]; ok {
|
||||||
|
nameData := val.(map[string]interface{})
|
||||||
|
if nameVal, ok := nameData["firstName"]; ok {
|
||||||
|
givenName := nameVal.(string)
|
||||||
|
user.GivenName = &givenName
|
||||||
|
}
|
||||||
|
|
||||||
|
if nameVal, ok := nameData["lastName"]; ok {
|
||||||
|
familyName := nameVal.(string)
|
||||||
|
user.FamilyName = &familyName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
@@ -99,13 +100,13 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||||||
provider := c.Param("oauth_provider")
|
provider := c.Param("oauth_provider")
|
||||||
isProviderConfigured := true
|
isProviderConfigured := true
|
||||||
switch provider {
|
switch provider {
|
||||||
case constants.SignupMethodGoogle:
|
case constants.AuthRecipeMethodGoogle:
|
||||||
if oauth.OAuthProviders.GoogleConfig == nil {
|
if oauth.OAuthProviders.GoogleConfig == nil {
|
||||||
log.Debug("Google OAuth provider is not configured")
|
log.Debug("Google OAuth provider is not configured")
|
||||||
isProviderConfigured = false
|
isProviderConfigured = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err := memorystore.Provider.SetState(oauthStateString, constants.SignupMethodGoogle)
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodGoogle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error setting state: ", err)
|
log.Debug("Error setting state: ", err)
|
||||||
c.JSON(500, gin.H{
|
c.JSON(500, gin.H{
|
||||||
@@ -114,16 +115,16 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// during the init of OAuthProvider authorizer url might be empty
|
// during the init of OAuthProvider authorizer url might be empty
|
||||||
oauth.OAuthProviders.GoogleConfig.RedirectURL = hostname + "/oauth_callback/google"
|
oauth.OAuthProviders.GoogleConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodGoogle
|
||||||
url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
case constants.SignupMethodGithub:
|
case constants.AuthRecipeMethodGithub:
|
||||||
if oauth.OAuthProviders.GithubConfig == nil {
|
if oauth.OAuthProviders.GithubConfig == nil {
|
||||||
log.Debug("Github OAuth provider is not configured")
|
log.Debug("Github OAuth provider is not configured")
|
||||||
isProviderConfigured = false
|
isProviderConfigured = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err := memorystore.Provider.SetState(oauthStateString, constants.SignupMethodGithub)
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodGithub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error setting state: ", err)
|
log.Debug("Error setting state: ", err)
|
||||||
c.JSON(500, gin.H{
|
c.JSON(500, gin.H{
|
||||||
@@ -131,16 +132,16 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
oauth.OAuthProviders.GithubConfig.RedirectURL = hostname + "/oauth_callback/github"
|
oauth.OAuthProviders.GithubConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodGithub
|
||||||
url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
case constants.SignupMethodFacebook:
|
case constants.AuthRecipeMethodFacebook:
|
||||||
if oauth.OAuthProviders.FacebookConfig == nil {
|
if oauth.OAuthProviders.FacebookConfig == nil {
|
||||||
log.Debug("Facebook OAuth provider is not configured")
|
log.Debug("Facebook OAuth provider is not configured")
|
||||||
isProviderConfigured = false
|
isProviderConfigured = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err := memorystore.Provider.SetState(oauthStateString, constants.SignupMethodFacebook)
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodFacebook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error setting state: ", err)
|
log.Debug("Error setting state: ", err)
|
||||||
c.JSON(500, gin.H{
|
c.JSON(500, gin.H{
|
||||||
@@ -148,9 +149,45 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
oauth.OAuthProviders.FacebookConfig.RedirectURL = hostname + "/oauth_callback/facebook"
|
oauth.OAuthProviders.FacebookConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodFacebook
|
||||||
url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
|
case constants.AuthRecipeMethodLinkedIn:
|
||||||
|
if oauth.OAuthProviders.LinkedInConfig == nil {
|
||||||
|
log.Debug("Linkedin OAuth provider is not configured")
|
||||||
|
isProviderConfigured = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodLinkedIn)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error setting state: ", err)
|
||||||
|
c.JSON(500, gin.H{
|
||||||
|
"error": "internal server error",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oauth.OAuthProviders.LinkedInConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodLinkedIn
|
||||||
|
url := oauth.OAuthProviders.LinkedInConfig.AuthCodeURL(oauthStateString)
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
|
case constants.AuthRecipeMethodApple:
|
||||||
|
if oauth.OAuthProviders.AppleConfig == nil {
|
||||||
|
log.Debug("Apple OAuth provider is not configured")
|
||||||
|
isProviderConfigured = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodApple)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error setting state: ", err)
|
||||||
|
c.JSON(500, gin.H{
|
||||||
|
"error": "internal server error",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oauth.OAuthProviders.AppleConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodApple
|
||||||
|
// there is scope encoding issue with oauth2 and how apple expects, hence added scope manually
|
||||||
|
// check: https://github.com/golang/oauth2/issues/449
|
||||||
|
url := oauth.OAuthProviders.AppleConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("response_mode", "form_post")) + "&scope=name email"
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
default:
|
default:
|
||||||
log.Debug("Invalid oauth provider: ", provider)
|
log.Debug("Invalid oauth provider: ", provider)
|
||||||
c.JSON(422, gin.H{
|
c.JSON(422, gin.H{
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Revoke handler to revoke refresh token
|
// Revoke handler to revoke refresh token
|
||||||
@@ -45,7 +46,24 @@ func RevokeHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.RemoveState(refreshToken)
|
claims, err := token.ParseJWTToken(refreshToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Client ID is invalid: ", clientID)
|
||||||
|
gc.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
"error_description": "Failed to parse jwt",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := claims["sub"].(string)
|
||||||
|
loginMethod := claims["login_method"]
|
||||||
|
sessionToken := userID
|
||||||
|
if loginMethod != nil && loginMethod != "" {
|
||||||
|
sessionToken = loginMethod.(string) + ":" + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
memorystore.Provider.DeleteUserSession(sessionToken, claims["nonce"].(string))
|
||||||
|
|
||||||
gc.JSON(http.StatusOK, gin.H{
|
gc.JSON(http.StatusOK, gin.H{
|
||||||
"message": "Token revoked successfully",
|
"message": "Token revoked successfully",
|
||||||
|
@@ -72,6 +72,9 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
var userID string
|
var userID string
|
||||||
var roles, scope []string
|
var roles, scope []string
|
||||||
|
loginMethod := ""
|
||||||
|
sessionKey := ""
|
||||||
|
|
||||||
if isAuthorizationCodeGrant {
|
if isAuthorizationCodeGrant {
|
||||||
|
|
||||||
if codeVerifier == "" {
|
if codeVerifier == "" {
|
||||||
@@ -107,6 +110,7 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go memorystore.Provider.RemoveState(encryptedCode)
|
||||||
// split session data
|
// split session data
|
||||||
// it contains code@sessiontoken
|
// it contains code@sessiontoken
|
||||||
sessionDataSplit := strings.Split(sessionData, "@")
|
sessionDataSplit := strings.Split(sessionData, "@")
|
||||||
@@ -130,11 +134,16 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// rollover the session for security
|
|
||||||
memorystore.Provider.RemoveState(sessionDataSplit[1])
|
|
||||||
userID = claims.Subject
|
userID = claims.Subject
|
||||||
roles = claims.Roles
|
roles = claims.Roles
|
||||||
scope = claims.Scope
|
scope = claims.Scope
|
||||||
|
loginMethod = claims.LoginMethod
|
||||||
|
// rollover the session for security
|
||||||
|
sessionKey = userID
|
||||||
|
if loginMethod != "" {
|
||||||
|
sessionKey = loginMethod + ":" + userID
|
||||||
|
}
|
||||||
|
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||||
} else {
|
} else {
|
||||||
// validate refresh token
|
// validate refresh token
|
||||||
if refreshToken == "" {
|
if refreshToken == "" {
|
||||||
@@ -154,6 +163,7 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
userID = claims["sub"].(string)
|
userID = claims["sub"].(string)
|
||||||
|
loginMethod := claims["login_method"]
|
||||||
rolesInterface := claims["roles"].([]interface{})
|
rolesInterface := claims["roles"].([]interface{})
|
||||||
scopeInterface := claims["scope"].([]interface{})
|
scopeInterface := claims["scope"].([]interface{})
|
||||||
for _, v := range rolesInterface {
|
for _, v := range rolesInterface {
|
||||||
@@ -162,8 +172,22 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
for _, v := range scopeInterface {
|
for _, v := range scopeInterface {
|
||||||
scope = append(scope, v.(string))
|
scope = append(scope, v.(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionKey = userID
|
||||||
|
if loginMethod != nil && loginMethod != "" {
|
||||||
|
sessionKey = loginMethod.(string) + ":" + sessionKey
|
||||||
|
}
|
||||||
// remove older refresh token and rotate it for security
|
// remove older refresh token and rotate it for security
|
||||||
memorystore.Provider.RemoveState(refreshToken)
|
go memorystore.Provider.DeleteUserSession(sessionKey, claims["nonce"].(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sessionKey == "" {
|
||||||
|
log.Debug("Error getting sessionKey: ", sessionKey, loginMethod)
|
||||||
|
gc.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"error": "unauthorized",
|
||||||
|
"error_description": "User not found",
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.Provider.GetUserByID(userID)
|
user, err := db.Provider.GetUserByID(userID)
|
||||||
@@ -176,7 +200,7 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error creating auth token: ", err)
|
log.Debug("Error creating auth token: ", err)
|
||||||
gc.JSON(http.StatusUnauthorized, gin.H{
|
gc.JSON(http.StatusUnauthorized, gin.H{
|
||||||
@@ -185,8 +209,8 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
|
||||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
@@ -204,7 +228,7 @@ func TokenHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res["refresh_token"] = authToken.RefreshToken.Token
|
res["refresh_token"] = authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.JSON(http.StatusOK, res)
|
gc.JSON(http.StatusOK, res)
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
@@ -42,7 +43,7 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
// verify if token exists in db
|
// verify if token exists in db
|
||||||
hostname := parsers.GetHost(c)
|
hostname := parsers.GetHost(c)
|
||||||
claim, err := token.ParseJWTToken(tokenInQuery, hostname, verificationRequest.Nonce, verificationRequest.Email)
|
claim, err := token.ParseJWTToken(tokenInQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error parsing token: ", err)
|
log.Debug("Error parsing token: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error_description"] = err.Error()
|
||||||
@@ -50,7 +51,14 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.Provider.GetUserByEmail(claim["sub"].(string))
|
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
||||||
|
log.Debug("Error validating jwt claims: ", err)
|
||||||
|
errorRes["error_description"] = err.Error()
|
||||||
|
c.JSON(400, errorRes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := db.Provider.GetUserByEmail(verificationRequest.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error getting user: ", err)
|
log.Debug("Error getting user: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error_description"] = err.Error()
|
||||||
@@ -84,7 +92,11 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
} else {
|
} else {
|
||||||
scope = strings.Split(scopeString, " ")
|
scope = strings.Split(scopeString, " ")
|
||||||
}
|
}
|
||||||
authToken, err := token.CreateAuthToken(c, user, roles, scope)
|
loginMethod := constants.AuthRecipeMethodBasicAuth
|
||||||
|
if verificationRequest.Identifier == constants.VerificationTypeMagicLinkLogin {
|
||||||
|
loginMethod = constants.AuthRecipeMethodMagicLinkLogin
|
||||||
|
}
|
||||||
|
authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error creating auth token: ", err)
|
log.Debug("Error creating auth token: ", err)
|
||||||
errorRes["error_description"] = err.Error()
|
errorRes["error_description"] = err.Error()
|
||||||
@@ -99,13 +111,14 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
|
|
||||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token
|
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token
|
||||||
|
|
||||||
|
sessionKey := loginMethod + ":" + user.ID
|
||||||
cookie.SetSession(c, authToken.FingerPrintHash)
|
cookie.SetSession(c, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
params = params + `&refresh_token=${refresh_token}`
|
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectURL == "" {
|
if redirectURL == "" {
|
||||||
@@ -115,7 +128,7 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
|||||||
if strings.Contains(redirectURL, "?") {
|
if strings.Contains(redirectURL, "?") {
|
||||||
redirectURL = redirectURL + "&" + params
|
redirectURL = redirectURL + "&" + params
|
||||||
} else {
|
} else {
|
||||||
redirectURL = redirectURL + "?" + params
|
redirectURL = redirectURL + "?" + strings.TrimPrefix(params, "&")
|
||||||
}
|
}
|
||||||
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
|
@@ -30,6 +30,7 @@ func InitMemStore() error {
|
|||||||
constants.EnvKeyDisableEmailVerification: false,
|
constants.EnvKeyDisableEmailVerification: false,
|
||||||
constants.EnvKeyDisableLoginPage: false,
|
constants.EnvKeyDisableLoginPage: false,
|
||||||
constants.EnvKeyDisableSignUp: false,
|
constants.EnvKeyDisableSignUp: false,
|
||||||
|
constants.EnvKeyDisableStrongPassword: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv()
|
requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv()
|
||||||
|
@@ -2,24 +2,23 @@ package inmemory
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore/providers/inmemory/stores"
|
||||||
)
|
)
|
||||||
|
|
||||||
type provider struct {
|
type provider struct {
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
sessionStore map[string]map[string]string
|
sessionStore *stores.SessionStore
|
||||||
stateStore map[string]string
|
stateStore *stores.StateStore
|
||||||
envStore *EnvStore
|
envStore *stores.EnvStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInMemoryStore returns a new in-memory store.
|
// NewInMemoryStore returns a new in-memory store.
|
||||||
func NewInMemoryProvider() (*provider, error) {
|
func NewInMemoryProvider() (*provider, error) {
|
||||||
return &provider{
|
return &provider{
|
||||||
mutex: sync.Mutex{},
|
mutex: sync.Mutex{},
|
||||||
sessionStore: map[string]map[string]string{},
|
envStore: stores.NewEnvStore(),
|
||||||
stateStore: map[string]string{},
|
sessionStore: stores.NewSessionStore(),
|
||||||
envStore: &EnvStore{
|
stateStore: stores.NewStateStore(),
|
||||||
mutex: sync.Mutex{},
|
|
||||||
store: map[string]interface{}{},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@@ -3,85 +3,76 @@ package inmemory
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClearStore clears the in-memory store.
|
// SetUserSession sets the user session
|
||||||
func (c *provider) ClearStore() error {
|
func (c *provider) SetUserSession(userId, key, token string) error {
|
||||||
if os.Getenv("ENV") != "test" {
|
c.sessionStore.Set(userId, key, token)
|
||||||
c.mutex.Lock()
|
|
||||||
defer c.mutex.Unlock()
|
|
||||||
}
|
|
||||||
c.sessionStore = map[string]map[string]string{}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserSessions returns all the user session token from the in-memory store.
|
// GetAllUserSessions returns all the user sessions token from the in-memory store.
|
||||||
func (c *provider) GetUserSessions(userId string) map[string]string {
|
func (c *provider) GetAllUserSessions(userId string) (map[string]string, error) {
|
||||||
if os.Getenv("ENV") != "test" {
|
data := c.sessionStore.GetAll(userId)
|
||||||
c.mutex.Lock()
|
return data, nil
|
||||||
defer c.mutex.Unlock()
|
|
||||||
}
|
|
||||||
res := map[string]string{}
|
|
||||||
for k, v := range c.stateStore {
|
|
||||||
split := strings.Split(v, "@")
|
|
||||||
if split[1] == userId {
|
|
||||||
res[k] = split[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAllUserSession deletes all the user sessions from in-memory store.
|
// GetUserSession returns value for given session token
|
||||||
func (c *provider) DeleteAllUserSession(userId string) error {
|
func (c *provider) GetUserSession(userId, sessionToken string) (string, error) {
|
||||||
if os.Getenv("ENV") != "test" {
|
return c.sessionStore.Get(userId, sessionToken), nil
|
||||||
c.mutex.Lock()
|
}
|
||||||
defer c.mutex.Unlock()
|
|
||||||
}
|
// DeleteAllUserSessions deletes all the user sessions from in-memory store.
|
||||||
sessions := c.GetUserSessions(userId)
|
func (c *provider) DeleteAllUserSessions(userId string) error {
|
||||||
for k := range sessions {
|
namespaces := []string{
|
||||||
c.RemoveState(k)
|
constants.AuthRecipeMethodBasicAuth,
|
||||||
|
constants.AuthRecipeMethodMagicLinkLogin,
|
||||||
|
constants.AuthRecipeMethodApple,
|
||||||
|
constants.AuthRecipeMethodFacebook,
|
||||||
|
constants.AuthRecipeMethodGithub,
|
||||||
|
constants.AuthRecipeMethodGoogle,
|
||||||
|
constants.AuthRecipeMethodLinkedIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, namespace := range namespaces {
|
||||||
|
c.sessionStore.RemoveAll(namespace + ":" + userId)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUserSession deletes the user session from the in-memory store.
|
||||||
|
func (c *provider) DeleteUserSession(userId, sessionToken string) error {
|
||||||
|
c.sessionStore.Remove(userId, sessionToken)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSessionForNamespace to delete session for a given namespace example google,github
|
||||||
|
func (c *provider) DeleteSessionForNamespace(namespace string) error {
|
||||||
|
c.sessionStore.RemoveByNamespace(namespace)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetState sets the state in the in-memory store.
|
// SetState sets the state in the in-memory store.
|
||||||
func (c *provider) SetState(key, state string) error {
|
func (c *provider) SetState(key, state string) error {
|
||||||
if os.Getenv("ENV") != "test" {
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
}
|
}
|
||||||
c.stateStore[key] = state
|
c.stateStore.Set(key, state)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetState gets the state from the in-memory store.
|
// GetState gets the state from the in-memory store.
|
||||||
func (c *provider) GetState(key string) (string, error) {
|
func (c *provider) GetState(key string) (string, error) {
|
||||||
if os.Getenv("ENV") != "test" {
|
return c.stateStore.Get(key), nil
|
||||||
c.mutex.Lock()
|
|
||||||
defer c.mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
state := ""
|
|
||||||
if stateVal, ok := c.stateStore[key]; ok {
|
|
||||||
state = stateVal
|
|
||||||
}
|
|
||||||
|
|
||||||
return state, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveState removes the state from the in-memory store.
|
// RemoveState removes the state from the in-memory store.
|
||||||
func (c *provider) RemoveState(key string) error {
|
func (c *provider) RemoveState(key string) error {
|
||||||
if os.Getenv("ENV") != "test" {
|
c.stateStore.Remove(key)
|
||||||
c.mutex.Lock()
|
|
||||||
defer c.mutex.Unlock()
|
|
||||||
}
|
|
||||||
delete(c.stateStore, key)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
package inmemory
|
package stores
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnvStore struct to store the env variables
|
// EnvStore struct to store the env variables
|
||||||
@@ -11,9 +13,17 @@ type EnvStore struct {
|
|||||||
store map[string]interface{}
|
store map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEnvStore create a new env store
|
||||||
|
func NewEnvStore() *EnvStore {
|
||||||
|
return &EnvStore{
|
||||||
|
mutex: sync.Mutex{},
|
||||||
|
store: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateEnvStore to update the whole env store object
|
// UpdateEnvStore to update the whole env store object
|
||||||
func (e *EnvStore) UpdateStore(store map[string]interface{}) {
|
func (e *EnvStore) UpdateStore(store map[string]interface{}) {
|
||||||
if os.Getenv("ENV") != "test" {
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
e.mutex.Lock()
|
e.mutex.Lock()
|
||||||
defer e.mutex.Unlock()
|
defer e.mutex.Unlock()
|
||||||
}
|
}
|
||||||
@@ -26,26 +36,17 @@ func (e *EnvStore) UpdateStore(store map[string]interface{}) {
|
|||||||
|
|
||||||
// GetStore returns the env store
|
// GetStore returns the env store
|
||||||
func (e *EnvStore) GetStore() map[string]interface{} {
|
func (e *EnvStore) GetStore() map[string]interface{} {
|
||||||
if os.Getenv("ENV") != "test" {
|
|
||||||
e.mutex.Lock()
|
|
||||||
defer e.mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.store
|
return e.store
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the value of the key in evn store
|
// Get returns the value of the key in evn store
|
||||||
func (e *EnvStore) Get(key string) interface{} {
|
func (e *EnvStore) Get(key string) interface{} {
|
||||||
if os.Getenv("ENV") != "test" {
|
|
||||||
e.mutex.Lock()
|
|
||||||
defer e.mutex.Unlock()
|
|
||||||
}
|
|
||||||
return e.store[key]
|
return e.store[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the value of the key in env store
|
// Set sets the value of the key in env store
|
||||||
func (e *EnvStore) Set(key string, value interface{}) {
|
func (e *EnvStore) Set(key string, value interface{}) {
|
||||||
if os.Getenv("ENV") != "test" {
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
e.mutex.Lock()
|
e.mutex.Lock()
|
||||||
defer e.mutex.Unlock()
|
defer e.mutex.Unlock()
|
||||||
}
|
}
|
@@ -0,0 +1,83 @@
|
|||||||
|
package stores
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SessionStore struct to store the env variables
|
||||||
|
type SessionStore struct {
|
||||||
|
mutex sync.Mutex
|
||||||
|
store map[string]map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSessionStore create a new session store
|
||||||
|
func NewSessionStore() *SessionStore {
|
||||||
|
return &SessionStore{
|
||||||
|
mutex: sync.Mutex{},
|
||||||
|
store: make(map[string]map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the value of the key in state store
|
||||||
|
func (s *SessionStore) Get(key, subKey string) string {
|
||||||
|
return s.store[key][subKey]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the value of the key in state store
|
||||||
|
func (s *SessionStore) Set(key string, subKey, value string) {
|
||||||
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
}
|
||||||
|
if _, ok := s.store[key]; !ok {
|
||||||
|
s.store[key] = make(map[string]string)
|
||||||
|
}
|
||||||
|
s.store[key][subKey] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAll all values for given key
|
||||||
|
func (s *SessionStore) RemoveAll(key string) {
|
||||||
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
}
|
||||||
|
delete(s.store, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove value for given key and subkey
|
||||||
|
func (s *SessionStore) Remove(key, subKey string) {
|
||||||
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
}
|
||||||
|
if _, ok := s.store[key]; ok {
|
||||||
|
delete(s.store[key], subKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all the values for given key
|
||||||
|
func (s *SessionStore) GetAll(key string) map[string]string {
|
||||||
|
if _, ok := s.store[key]; !ok {
|
||||||
|
s.store[key] = make(map[string]string)
|
||||||
|
}
|
||||||
|
return s.store[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveByNamespace to delete session for a given namespace example google,github
|
||||||
|
func (s *SessionStore) RemoveByNamespace(namespace string) error {
|
||||||
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
for key := range s.store {
|
||||||
|
if strings.Contains(key, namespace+":") {
|
||||||
|
delete(s.store, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
46
server/memorystore/providers/inmemory/stores/state_store.go
Normal file
46
server/memorystore/providers/inmemory/stores/state_store.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package stores
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StateStore struct to store the env variables
|
||||||
|
type StateStore struct {
|
||||||
|
mutex sync.Mutex
|
||||||
|
store map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStateStore create a new state store
|
||||||
|
func NewStateStore() *StateStore {
|
||||||
|
return &StateStore{
|
||||||
|
mutex: sync.Mutex{},
|
||||||
|
store: make(map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the value of the key in state store
|
||||||
|
func (s *StateStore) Get(key string) string {
|
||||||
|
return s.store[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the value of the key in state store
|
||||||
|
func (s *StateStore) Set(key string, value string) {
|
||||||
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
}
|
||||||
|
s.store[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the key from state store
|
||||||
|
func (s *StateStore) Remove(key string) {
|
||||||
|
if os.Getenv("ENV") != constants.TestEnv {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(s.store, key)
|
||||||
|
}
|
@@ -2,12 +2,19 @@ package providers
|
|||||||
|
|
||||||
// Provider defines current memory store provider
|
// Provider defines current memory store provider
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
|
// SetUserSession sets the user session
|
||||||
|
SetUserSession(userId, key, token string) error
|
||||||
|
// GetAllUserSessions returns all the user sessions from the session store
|
||||||
|
GetAllUserSessions(userId string) (map[string]string, error)
|
||||||
|
// GetUserSession returns the session token for given token
|
||||||
|
GetUserSession(userId, key string) (string, error)
|
||||||
|
// DeleteUserSession deletes the user session
|
||||||
|
DeleteUserSession(userId, key string) error
|
||||||
// DeleteAllSessions deletes all the sessions from the session store
|
// DeleteAllSessions deletes all the sessions from the session store
|
||||||
DeleteAllUserSession(userId string) error
|
DeleteAllUserSessions(userId string) error
|
||||||
// GetUserSessions returns all the user sessions from the session store
|
// DeleteSessionForNamespace deletes the session for a given namespace
|
||||||
GetUserSessions(userId string) map[string]string
|
DeleteSessionForNamespace(namespace string) error
|
||||||
// ClearStore clears the session store for authorizer tokens
|
|
||||||
ClearStore() error
|
|
||||||
// SetState sets the login state (key, value form) in the session store
|
// SetState sets the login state (key, value form) in the session store
|
||||||
SetState(key, state string) error
|
SetState(key, state string) error
|
||||||
// GetState returns the state from the session store
|
// GetState returns the state from the session store
|
||||||
|
@@ -2,59 +2,107 @@ package redis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// session store prefix
|
// state store prefix
|
||||||
sessionStorePrefix = "authorizer_session:"
|
stateStorePrefix = "authorizer_state:"
|
||||||
// env store prefix
|
// env store prefix
|
||||||
envStorePrefix = "authorizer_env"
|
envStorePrefix = "authorizer_env"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClearStore clears the redis store for authorizer related tokens
|
// SetUserSession sets the user session in redis store.
|
||||||
func (c *provider) ClearStore() error {
|
func (c *provider) SetUserSession(userId, key, token string) error {
|
||||||
err := c.store.Del(c.ctx, sessionStorePrefix+"*").Err()
|
err := c.store.HSet(c.ctx, userId, key, token).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error clearing redis store: ", err)
|
log.Debug("Error saving to redis: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserSessions returns all the user session token from the redis store.
|
// GetAllUserSessions returns all the user session token from the redis store.
|
||||||
func (c *provider) GetUserSessions(userID string) map[string]string {
|
func (c *provider) GetAllUserSessions(userID string) (map[string]string, error) {
|
||||||
data, err := c.store.HGetAll(c.ctx, "*").Result()
|
data, err := c.store.HGetAll(c.ctx, userID).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error getting token from redis store: ", err)
|
log.Debug("error getting all user sessions from redis store: ", err)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := map[string]string{}
|
return data, nil
|
||||||
for k, v := range data {
|
|
||||||
split := strings.Split(v, "@")
|
|
||||||
if split[1] == userID {
|
|
||||||
res[k] = split[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAllUserSession deletes all the user session from redis
|
// GetUserSession returns the user session from redis store.
|
||||||
func (c *provider) DeleteAllUserSession(userId string) error {
|
func (c *provider) GetUserSession(userId, key string) (string, error) {
|
||||||
sessions := c.GetUserSessions(userId)
|
data, err := c.store.HGet(c.ctx, userId, key).Result()
|
||||||
for k, v := range sessions {
|
if err != nil {
|
||||||
if k == "token" {
|
return "", err
|
||||||
err := c.store.Del(c.ctx, v).Err()
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUserSession deletes the user session from redis store.
|
||||||
|
func (c *provider) DeleteUserSession(userId, key string) error {
|
||||||
|
if err := c.store.HDel(c.ctx, userId, constants.TokenTypeSessionToken+"_"+key).Err(); err != nil {
|
||||||
|
log.Debug("Error deleting user session from redis: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.store.HDel(c.ctx, userId, constants.TokenTypeAccessToken+"_"+key).Err(); err != nil {
|
||||||
|
log.Debug("Error deleting user session from redis: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.store.HDel(c.ctx, userId, constants.TokenTypeRefreshToken+"_"+key).Err(); err != nil {
|
||||||
|
log.Debug("Error deleting user session from redis: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAllUserSessions deletes all the user session from redis
|
||||||
|
func (c *provider) DeleteAllUserSessions(userID string) error {
|
||||||
|
namespaces := []string{
|
||||||
|
constants.AuthRecipeMethodBasicAuth,
|
||||||
|
constants.AuthRecipeMethodMagicLinkLogin,
|
||||||
|
constants.AuthRecipeMethodApple,
|
||||||
|
constants.AuthRecipeMethodFacebook,
|
||||||
|
constants.AuthRecipeMethodGithub,
|
||||||
|
constants.AuthRecipeMethodGoogle,
|
||||||
|
constants.AuthRecipeMethodLinkedIn,
|
||||||
|
}
|
||||||
|
for _, namespace := range namespaces {
|
||||||
|
err := c.store.Del(c.ctx, namespace+":"+userID).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error deleting all user sessions from redis: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSessionForNamespace to delete session for a given namespace example google,github
|
||||||
|
func (c *provider) DeleteSessionForNamespace(namespace string) error {
|
||||||
|
var cursor uint64
|
||||||
|
for {
|
||||||
|
keys := []string{}
|
||||||
|
keys, cursor, err := c.store.Scan(c.ctx, cursor, namespace+":*", 0).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Error scanning keys for %s namespace: %s", namespace, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
err := c.store.Del(c.ctx, key).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error deleting redis token: ", err)
|
log.Debugf("Error deleting sessions for %s namespace: %s", namespace, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cursor == 0 { // no more keys
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -62,7 +110,7 @@ func (c *provider) DeleteAllUserSession(userId string) error {
|
|||||||
|
|
||||||
// SetState sets the state in redis store.
|
// SetState sets the state in redis store.
|
||||||
func (c *provider) SetState(key, value string) error {
|
func (c *provider) SetState(key, value string) error {
|
||||||
err := c.store.Set(c.ctx, sessionStorePrefix+key, value, 0).Err()
|
err := c.store.Set(c.ctx, stateStorePrefix+key, value, 0).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error saving redis token: ", err)
|
log.Debug("Error saving redis token: ", err)
|
||||||
return err
|
return err
|
||||||
@@ -73,18 +121,18 @@ func (c *provider) SetState(key, value string) error {
|
|||||||
|
|
||||||
// GetState gets the state from redis store.
|
// GetState gets the state from redis store.
|
||||||
func (c *provider) GetState(key string) (string, error) {
|
func (c *provider) GetState(key string) (string, error) {
|
||||||
var res string
|
data, err := c.store.Get(c.ctx, stateStorePrefix+key).Result()
|
||||||
err := c.store.Get(c.ctx, sessionStorePrefix+key).Scan(&res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error getting token from redis store: ", err)
|
log.Debug("error getting token from redis store: ", err)
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveState removes the state from redis store.
|
// RemoveState removes the state from redis store.
|
||||||
func (c *provider) RemoveState(key string) error {
|
func (c *provider) RemoveState(key string) error {
|
||||||
err := c.store.Del(c.ctx, sessionStorePrefix+key).Err()
|
err := c.store.Del(c.ctx, stateStorePrefix+key).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Error deleting redis token: ", err)
|
log.Fatalln("Error deleting redis token: ", err)
|
||||||
return err
|
return err
|
||||||
@@ -112,7 +160,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for key, value := range data {
|
for key, value := range data {
|
||||||
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp {
|
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword {
|
||||||
boolValue, err := strconv.ParseBool(value)
|
boolValue, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
@@ -137,22 +185,20 @@ func (c *provider) UpdateEnvVariable(key string, value interface{}) error {
|
|||||||
|
|
||||||
// GetStringStoreEnvVariable to get the string env variable from env store
|
// GetStringStoreEnvVariable to get the string env variable from env store
|
||||||
func (c *provider) GetStringStoreEnvVariable(key string) (string, error) {
|
func (c *provider) GetStringStoreEnvVariable(key string) (string, error) {
|
||||||
var res string
|
data, err := c.store.HGet(c.ctx, envStorePrefix, key).Result()
|
||||||
err := c.store.HGet(c.ctx, envStorePrefix, key).Scan(&res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBoolStoreEnvVariable to get the bool env variable from env store
|
// GetBoolStoreEnvVariable to get the bool env variable from env store
|
||||||
func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) {
|
func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) {
|
||||||
var res bool
|
data, err := c.store.HGet(c.ctx, envStorePrefix, key).Result()
|
||||||
err := c.store.HGet(c.ctx, envStorePrefix, key).Scan(res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return data == "1", nil
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
facebookOAuth2 "golang.org/x/oauth2/facebook"
|
facebookOAuth2 "golang.org/x/oauth2/facebook"
|
||||||
githubOAuth2 "golang.org/x/oauth2/github"
|
githubOAuth2 "golang.org/x/oauth2/github"
|
||||||
|
linkedInOAuth2 "golang.org/x/oauth2/linkedin"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
@@ -17,6 +18,8 @@ type OAuthProvider struct {
|
|||||||
GoogleConfig *oauth2.Config
|
GoogleConfig *oauth2.Config
|
||||||
GithubConfig *oauth2.Config
|
GithubConfig *oauth2.Config
|
||||||
FacebookConfig *oauth2.Config
|
FacebookConfig *oauth2.Config
|
||||||
|
LinkedInConfig *oauth2.Config
|
||||||
|
AppleConfig *oauth2.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// OIDCProviders is a struct that contains reference all the OpenID providers
|
// OIDCProviders is a struct that contains reference all the OpenID providers
|
||||||
@@ -92,5 +95,43 @@ func InitOAuth() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkedInClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientID)
|
||||||
|
if err != nil {
|
||||||
|
linkedInClientID = ""
|
||||||
|
}
|
||||||
|
linkedInClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
linkedInClientSecret = ""
|
||||||
|
}
|
||||||
|
if linkedInClientID != "" && linkedInClientSecret != "" {
|
||||||
|
OAuthProviders.LinkedInConfig = &oauth2.Config{
|
||||||
|
ClientID: linkedInClientID,
|
||||||
|
ClientSecret: linkedInClientSecret,
|
||||||
|
RedirectURL: "/oauth_callback/linkedin",
|
||||||
|
Endpoint: linkedInOAuth2.Endpoint,
|
||||||
|
Scopes: []string{"r_liteprofile", "r_emailaddress"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appleClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientID)
|
||||||
|
if err != nil {
|
||||||
|
appleClientID = ""
|
||||||
|
}
|
||||||
|
appleClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
appleClientSecret = ""
|
||||||
|
}
|
||||||
|
if appleClientID != "" && appleClientSecret != "" {
|
||||||
|
OAuthProviders.AppleConfig = &oauth2.Config{
|
||||||
|
ClientID: appleClientID,
|
||||||
|
ClientSecret: appleClientSecret,
|
||||||
|
RedirectURL: "/oauth_callback/apple",
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: "https://appleid.apple.com/auth/authorize",
|
||||||
|
TokenURL: "https://appleid.apple.com/auth/token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -4,9 +4,10 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetHost returns hostname from request context
|
// GetHost returns hostname from request context
|
||||||
@@ -14,15 +15,15 @@ import (
|
|||||||
// if EnvKeyAuthorizerURL is set it is given second highest priority.
|
// if EnvKeyAuthorizerURL is set it is given second highest priority.
|
||||||
// if above 2 are not set the requesting host name is used
|
// if above 2 are not set the requesting host name is used
|
||||||
func GetHost(c *gin.Context) string {
|
func GetHost(c *gin.Context) string {
|
||||||
authorizerURL := c.Request.Header.Get("X-Authorizer-URL")
|
authorizerURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)
|
||||||
|
if err != nil {
|
||||||
|
authorizerURL = ""
|
||||||
|
}
|
||||||
if authorizerURL != "" {
|
if authorizerURL != "" {
|
||||||
return authorizerURL
|
return authorizerURL
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizerURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)
|
authorizerURL = c.Request.Header.Get("X-Authorizer-URL")
|
||||||
if err == nil {
|
|
||||||
authorizerURL = ""
|
|
||||||
}
|
|
||||||
if authorizerURL != "" {
|
if authorizerURL != "" {
|
||||||
return authorizerURL
|
return authorizerURL
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go memorystore.Provider.DeleteAllUserSession(fmt.Sprintf("%x", user.ID))
|
go memorystore.Provider.DeleteAllUserSessions(user.ID)
|
||||||
|
|
||||||
err = db.Provider.DeleteUser(user)
|
err = db.Provider.DeleteUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -130,6 +130,18 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
|||||||
if val, ok := store[constants.EnvKeyGithubClientSecret]; ok {
|
if val, ok := store[constants.EnvKeyGithubClientSecret]; ok {
|
||||||
res.GithubClientSecret = utils.NewStringRef(val.(string))
|
res.GithubClientSecret = utils.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyLinkedInClientID]; ok {
|
||||||
|
res.LinkedinClientID = utils.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyLinkedInClientSecret]; ok {
|
||||||
|
res.LinkedinClientSecret = utils.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyAppleClientID]; ok {
|
||||||
|
res.AppleClientID = utils.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyAppleClientSecret]; ok {
|
||||||
|
res.AppleClientSecret = utils.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
if val, ok := store[constants.EnvKeyOrganizationName]; ok {
|
if val, ok := store[constants.EnvKeyOrganizationName]; ok {
|
||||||
res.OrganizationName = utils.NewStringRef(val.(string))
|
res.OrganizationName = utils.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
@@ -141,7 +153,14 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
|||||||
res.AllowedOrigins = strings.Split(store[constants.EnvKeyAllowedOrigins].(string), ",")
|
res.AllowedOrigins = strings.Split(store[constants.EnvKeyAllowedOrigins].(string), ",")
|
||||||
res.Roles = strings.Split(store[constants.EnvKeyRoles].(string), ",")
|
res.Roles = strings.Split(store[constants.EnvKeyRoles].(string), ",")
|
||||||
res.DefaultRoles = strings.Split(store[constants.EnvKeyDefaultRoles].(string), ",")
|
res.DefaultRoles = strings.Split(store[constants.EnvKeyDefaultRoles].(string), ",")
|
||||||
res.ProtectedRoles = strings.Split(store[constants.EnvKeyProtectedRoles].(string), ",")
|
// since protected role is optional default split gives array with empty string
|
||||||
|
protectedRoles := strings.Split(store[constants.EnvKeyProtectedRoles].(string), ",")
|
||||||
|
res.ProtectedRoles = []string{}
|
||||||
|
for _, role := range protectedRoles {
|
||||||
|
if strings.Trim(role, " ") != "" {
|
||||||
|
res.ProtectedRoles = append(res.ProtectedRoles, strings.Trim(role, " "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// bool vars
|
// bool vars
|
||||||
res.DisableEmailVerification = store[constants.EnvKeyDisableEmailVerification].(bool)
|
res.DisableEmailVerification = store[constants.EnvKeyDisableEmailVerification].(bool)
|
||||||
@@ -149,6 +168,7 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
|||||||
res.DisableMagicLinkLogin = store[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
res.DisableMagicLinkLogin = store[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
res.DisableLoginPage = store[constants.EnvKeyDisableLoginPage].(bool)
|
res.DisableLoginPage = store[constants.EnvKeyDisableLoginPage].(bool)
|
||||||
res.DisableSignUp = store[constants.EnvKeyDisableSignUp].(bool)
|
res.DisableSignUp = store[constants.EnvKeyDisableSignUp].(bool)
|
||||||
|
res.DisableStrongPassword = store[constants.EnvKeyDisableStrongPassword].(bool)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@@ -129,11 +129,11 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput)
|
|||||||
|
|
||||||
// use magic link login if that option is on
|
// use magic link login if that option is on
|
||||||
if !isMagicLinkLoginDisabled {
|
if !isMagicLinkLoginDisabled {
|
||||||
user.SignupMethods = constants.SignupMethodMagicLinkLogin
|
user.SignupMethods = constants.AuthRecipeMethodMagicLinkLogin
|
||||||
verificationRequest.Identifier = constants.VerificationTypeMagicLinkLogin
|
verificationRequest.Identifier = constants.VerificationTypeMagicLinkLogin
|
||||||
} else {
|
} else {
|
||||||
// use basic authentication if that option is on
|
// use basic authentication if that option is on
|
||||||
user.SignupMethods = constants.SignupMethodBasicAuth
|
user.SignupMethods = constants.AuthRecipeMethodBasicAuth
|
||||||
verificationRequest.Identifier = constants.VerificationTypeForgotPassword
|
verificationRequest.Identifier = constants.VerificationTypeForgotPassword
|
||||||
|
|
||||||
verifyEmailURL = appURL + "/setup-password"
|
verifyEmailURL = appURL + "/setup-password"
|
||||||
|
@@ -56,7 +56,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||||||
return res, fmt.Errorf(`user access has been revoked`)
|
return res, fmt.Errorf(`user access has been revoked`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(user.SignupMethods, constants.SignupMethodBasicAuth) {
|
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodBasicAuth) {
|
||||||
log.Debug("User signup method is not basic auth")
|
log.Debug("User signup method is not basic auth")
|
||||||
return res, fmt.Errorf(`user has not signed up email & password`)
|
return res, fmt.Errorf(`user has not signed up email & password`)
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||||||
scope = params.Scope
|
scope = params.Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to create auth token", err)
|
log.Debug("Failed to create auth token", err)
|
||||||
return res, err
|
return res, err
|
||||||
@@ -117,12 +117,13 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
sessionStoreKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res.RefreshToken = &authToken.RefreshToken.Token
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
|
@@ -2,6 +2,7 @@ package resolvers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@@ -9,38 +10,46 @@ import (
|
|||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogoutResolver is a resolver for logout mutation
|
// LogoutResolver is a resolver for logout mutation
|
||||||
func LogoutResolver(ctx context.Context) (*model.Response, error) {
|
func LogoutResolver(ctx context.Context) (*model.Response, error) {
|
||||||
var res *model.Response
|
|
||||||
|
|
||||||
gc, err := utils.GinContextFromContext(ctx)
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get GinContext: ", err)
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get fingerprint hash
|
// get fingerprint hash
|
||||||
fingerprintHash, err := cookie.GetSession(gc)
|
fingerprintHash, err := cookie.GetSession(gc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get fingerprint hash: ", err)
|
log.Debug("Failed to get fingerprint hash: ", err)
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
decryptedFingerPrint, err := crypto.DecryptAES(fingerprintHash)
|
decryptedFingerPrint, err := crypto.DecryptAES(fingerprintHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to decrypt fingerprint hash: ", err)
|
log.Debug("Failed to decrypt fingerprint hash: ", err)
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fingerPrint := string(decryptedFingerPrint)
|
var sessionData token.SessionData
|
||||||
|
err = json.Unmarshal([]byte(decryptedFingerPrint), &sessionData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
memorystore.Provider.RemoveState(fingerPrint)
|
sessionKey := sessionData.Subject
|
||||||
|
if sessionData.LoginMethod != "" {
|
||||||
|
sessionKey = sessionData.LoginMethod + ":" + sessionData.Subject
|
||||||
|
}
|
||||||
|
|
||||||
|
memorystore.Provider.DeleteUserSession(sessionKey, sessionData.Nonce)
|
||||||
cookie.DeleteSession(gc)
|
cookie.DeleteSession(gc)
|
||||||
|
|
||||||
res = &model.Response{
|
res := &model.Response{
|
||||||
Message: "Logged out successfully",
|
Message: "Logged out successfully",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -70,7 +70,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
|
|||||||
return res, fmt.Errorf(`signup is disabled for this instance`)
|
return res, fmt.Errorf(`signup is disabled for this instance`)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.SignupMethods = constants.SignupMethodMagicLinkLogin
|
user.SignupMethods = constants.AuthRecipeMethodMagicLinkLogin
|
||||||
// define roles for new user
|
// define roles for new user
|
||||||
if len(params.Roles) > 0 {
|
if len(params.Roles) > 0 {
|
||||||
// check if roles exists
|
// check if roles exists
|
||||||
@@ -158,8 +158,8 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
|
|||||||
}
|
}
|
||||||
|
|
||||||
signupMethod := existingUser.SignupMethods
|
signupMethod := existingUser.SignupMethods
|
||||||
if !strings.Contains(signupMethod, constants.SignupMethodMagicLinkLogin) {
|
if !strings.Contains(signupMethod, constants.AuthRecipeMethodMagicLinkLogin) {
|
||||||
signupMethod = signupMethod + "," + constants.SignupMethodMagicLinkLogin
|
signupMethod = signupMethod + "," + constants.AuthRecipeMethodMagicLinkLogin
|
||||||
}
|
}
|
||||||
|
|
||||||
user.SignupMethods = signupMethod
|
user.SignupMethods = signupMethod
|
||||||
@@ -197,7 +197,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
|
|||||||
if strings.Contains(redirectURL, "?") {
|
if strings.Contains(redirectURL, "?") {
|
||||||
redirectURL = redirectURL + "&" + redirectURLParams
|
redirectURL = redirectURL + "&" + redirectURLParams
|
||||||
} else {
|
} else {
|
||||||
redirectURL = redirectURL + "?" + redirectURLParams
|
redirectURL = redirectURL + "?" + strings.TrimPrefix(redirectURLParams, "&")
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationType := constants.VerificationTypeMagicLinkLogin
|
verificationType := constants.VerificationTypeMagicLinkLogin
|
||||||
|
@@ -41,6 +41,30 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
|
|||||||
facebookClientSecret = ""
|
facebookClientSecret = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkedClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientID)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get LinkedIn Client ID from environment variable", err)
|
||||||
|
linkedClientID = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedInClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyLinkedInClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get LinkedIn Client Secret from environment variable", err)
|
||||||
|
linkedInClientSecret = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
appleClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientID)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get Apple Client ID from environment variable", err)
|
||||||
|
appleClientID = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
appleClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppleClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get Apple Client Secret from environment variable", err)
|
||||||
|
appleClientSecret = ""
|
||||||
|
}
|
||||||
|
|
||||||
githubClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID)
|
githubClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get Github Client ID from environment variable", err)
|
log.Debug("Failed to get Github Client ID from environment variable", err)
|
||||||
@@ -77,16 +101,25 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
|
|||||||
isSignUpDisabled = true
|
isSignUpDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isStrongPasswordDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableStrongPassword)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get Disable Signup from environment variable", err)
|
||||||
|
isSignUpDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
metaInfo := model.Meta{
|
metaInfo := model.Meta{
|
||||||
Version: constants.VERSION,
|
Version: constants.VERSION,
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
IsGoogleLoginEnabled: googleClientID != "" && googleClientSecret != "",
|
IsGoogleLoginEnabled: googleClientID != "" && googleClientSecret != "",
|
||||||
IsGithubLoginEnabled: githubClientID != "" && githubClientSecret != "",
|
IsGithubLoginEnabled: githubClientID != "" && githubClientSecret != "",
|
||||||
IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "",
|
IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "",
|
||||||
|
IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "",
|
||||||
|
IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "",
|
||||||
IsBasicAuthenticationEnabled: !isBasicAuthDisabled,
|
IsBasicAuthenticationEnabled: !isBasicAuthDisabled,
|
||||||
IsEmailVerificationEnabled: !isEmailVerificationDisabled,
|
IsEmailVerificationEnabled: !isEmailVerificationDisabled,
|
||||||
IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled,
|
IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled,
|
||||||
IsSignUpEnabled: !isSignUpDisabled,
|
IsSignUpEnabled: !isSignUpDisabled,
|
||||||
|
IsStrongPasswordEnabled: !isStrongPasswordDisabled,
|
||||||
}
|
}
|
||||||
return &metaInfo, nil
|
return &metaInfo, nil
|
||||||
}
|
}
|
||||||
|
@@ -50,19 +50,24 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
|
|||||||
return res, fmt.Errorf(`passwords don't match`)
|
return res, fmt.Errorf(`passwords don't match`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validators.IsValidPassword(params.Password) {
|
if err := validators.IsValidPassword(params.Password); err != nil {
|
||||||
log.Debug("Invalid password")
|
log.Debug("Invalid password")
|
||||||
return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`)
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify if token exists in db
|
// verify if token exists in db
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email)
|
claim, err := token.ParseJWTToken(params.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to parse token: ", err)
|
log.Debug("Failed to parse token: ", err)
|
||||||
return res, fmt.Errorf(`invalid token`)
|
return res, fmt.Errorf(`invalid token`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
||||||
|
log.Debug("Failed to validate jwt claims: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid token`)
|
||||||
|
}
|
||||||
|
|
||||||
email := claim["sub"].(string)
|
email := claim["sub"].(string)
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"email": email,
|
"email": email,
|
||||||
@@ -77,8 +82,8 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
|
|||||||
user.Password = &password
|
user.Password = &password
|
||||||
|
|
||||||
signupMethod := user.SignupMethods
|
signupMethod := user.SignupMethods
|
||||||
if !strings.Contains(signupMethod, constants.SignupMethodBasicAuth) {
|
if !strings.Contains(signupMethod, constants.AuthRecipeMethodBasicAuth) {
|
||||||
signupMethod = signupMethod + "," + constants.SignupMethodBasicAuth
|
signupMethod = signupMethod + "," + constants.AuthRecipeMethodBasicAuth
|
||||||
}
|
}
|
||||||
user.SignupMethods = signupMethod
|
user.SignupMethods = signupMethod
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@ func RevokeAccessResolver(ctx context.Context, params model.UpdateAccessInput) (
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go memorystore.Provider.DeleteAllUserSession(fmt.Sprintf("%x", user.ID))
|
go memorystore.Provider.DeleteAllUserSessions(user.ID)
|
||||||
|
|
||||||
res = &model.Response{
|
res = &model.Response{
|
||||||
Message: `user access revoked successfully`,
|
Message: `user access revoked successfully`,
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
@@ -29,7 +30,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
|||||||
|
|
||||||
sessionToken, err := cookie.GetSession(gc)
|
sessionToken, err := cookie.GetSession(gc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get session token", err)
|
log.Debug("Failed to get session token: ", err)
|
||||||
return res, errors.New("unauthorized")
|
return res, errors.New("unauthorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,17 +70,18 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
|||||||
scope = params.Scope
|
scope = params.Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope)
|
authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope, claims.LoginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to create auth token: ", err)
|
log.Debug("Failed to create auth token: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// rollover the session for security
|
// rollover the session for security
|
||||||
memorystore.Provider.RemoveState(sessionToken)
|
sessionKey := userID
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
if claims.LoginMethod != "" {
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
sessionKey = claims.LoginMethod + ":" + userID
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
}
|
||||||
|
go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce)
|
||||||
|
|
||||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
if expiresIn <= 0 {
|
if expiresIn <= 0 {
|
||||||
@@ -94,10 +96,13 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
|||||||
User: user.AsAPIUser(),
|
User: user.AsAPIUser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res.RefreshToken = &authToken.RefreshToken.Token
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@@ -58,9 +58,9 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
|||||||
return res, fmt.Errorf(`password and confirm password does not match`)
|
return res, fmt.Errorf(`password and confirm password does not match`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validators.IsValidPassword(params.Password) {
|
if err := validators.IsValidPassword(params.Password); err != nil {
|
||||||
log.Debug("Invalid password")
|
log.Debug("Invalid password")
|
||||||
return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`)
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
params.Email = strings.ToLower(params.Email)
|
params.Email = strings.ToLower(params.Email)
|
||||||
@@ -100,7 +100,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
|||||||
} else {
|
} else {
|
||||||
roles = strings.Split(rolesString, ",")
|
roles = strings.Split(rolesString, ",")
|
||||||
}
|
}
|
||||||
if !validators.IsValidRoles(roles, params.Roles) {
|
if !validators.IsValidRoles(params.Roles, roles) {
|
||||||
log.Debug("Invalid roles: ", params.Roles)
|
log.Debug("Invalid roles: ", params.Roles)
|
||||||
return res, fmt.Errorf(`invalid roles`)
|
return res, fmt.Errorf(`invalid roles`)
|
||||||
} else {
|
} else {
|
||||||
@@ -157,7 +157,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
|||||||
user.Picture = params.Picture
|
user.Picture = params.Picture
|
||||||
}
|
}
|
||||||
|
|
||||||
user.SignupMethods = constants.SignupMethodBasicAuth
|
user.SignupMethods = constants.AuthRecipeMethodBasicAuth
|
||||||
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
|
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error getting email verification disabled: ", err)
|
log.Debug("Error getting email verification disabled: ", err)
|
||||||
@@ -219,14 +219,12 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
|||||||
scope = params.Scope
|
scope = params.Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to create auth token: ", err)
|
log.Debug("Failed to create auth token: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
UserAgent: utils.GetUserAgent(gc.Request),
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
@@ -244,6 +242,16 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
|||||||
ExpiresIn: &expiresIn,
|
ExpiresIn: &expiresIn,
|
||||||
User: userToReturn,
|
User: userToReturn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
|
@@ -21,6 +21,54 @@ import (
|
|||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// check if login methods have been disabled
|
||||||
|
// remove the session tokens for those methods
|
||||||
|
func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
|
isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
|
isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
|
isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != ""
|
||||||
|
isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
||||||
|
isCurrentGoogleLoginEnabled := currentData[constants.EnvKeyGoogleClientID] != nil && currentData[constants.EnvKeyGoogleClientSecret] != nil && currentData[constants.EnvKeyGoogleClientID].(string) != "" && currentData[constants.EnvKeyGoogleClientSecret].(string) != ""
|
||||||
|
isCurrentGithubLoginEnabled := currentData[constants.EnvKeyGithubClientID] != nil && currentData[constants.EnvKeyGithubClientSecret] != nil && currentData[constants.EnvKeyGithubClientID].(string) != "" && currentData[constants.EnvKeyGithubClientSecret].(string) != ""
|
||||||
|
isCurrentLinkedInLoginEnabled := currentData[constants.EnvKeyLinkedInClientID] != nil && currentData[constants.EnvKeyLinkedInClientSecret] != nil && currentData[constants.EnvKeyLinkedInClientID].(string) != "" && currentData[constants.EnvKeyLinkedInClientSecret].(string) != ""
|
||||||
|
|
||||||
|
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
|
isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
|
isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != ""
|
||||||
|
isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
||||||
|
isUpdatedGoogleLoginEnabled := updatedData[constants.EnvKeyGoogleClientID] != nil && updatedData[constants.EnvKeyGoogleClientSecret] != nil && updatedData[constants.EnvKeyGoogleClientID].(string) != "" && updatedData[constants.EnvKeyGoogleClientSecret].(string) != ""
|
||||||
|
isUpdatedGithubLoginEnabled := updatedData[constants.EnvKeyGithubClientID] != nil && updatedData[constants.EnvKeyGithubClientSecret] != nil && updatedData[constants.EnvKeyGithubClientID].(string) != "" && updatedData[constants.EnvKeyGithubClientSecret].(string) != ""
|
||||||
|
isUpdatedLinkedInLoginEnabled := updatedData[constants.EnvKeyLinkedInClientID] != nil && updatedData[constants.EnvKeyLinkedInClientSecret] != nil && updatedData[constants.EnvKeyLinkedInClientID].(string) != "" && updatedData[constants.EnvKeyLinkedInClientSecret].(string) != ""
|
||||||
|
|
||||||
|
if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCurrentAppleLoginEnabled && !isUpdatedAppleLoginEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodApple)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCurrentFacebookLoginEnabled && !isUpdatedFacebookLoginEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodFacebook)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCurrentGoogleLoginEnabled && !isUpdatedGoogleLoginEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGoogle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCurrentGithubLoginEnabled && !isUpdatedGithubLoginEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGithub)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCurrentLinkedInLoginEnabled && !isUpdatedLinkedInLoginEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodLinkedIn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateEnvResolver is a resolver for update config mutation
|
// UpdateEnvResolver is a resolver for update config mutation
|
||||||
// This is admin only mutation
|
// This is admin only mutation
|
||||||
func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) {
|
func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) {
|
||||||
@@ -37,12 +85,19 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
|
|||||||
return res, fmt.Errorf("unauthorized")
|
return res, fmt.Errorf("unauthorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedData, err := memorystore.Provider.GetEnvStore()
|
currentData, err := memorystore.Provider.GetEnvStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get env store: ", err)
|
log.Debug("Failed to get env store: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clone currentData in new var
|
||||||
|
// that will be updated based on the req
|
||||||
|
updatedData := make(map[string]interface{})
|
||||||
|
for key, val := range currentData {
|
||||||
|
updatedData[key] = val
|
||||||
|
}
|
||||||
|
|
||||||
isJWTUpdated := false
|
isJWTUpdated := false
|
||||||
algo := updatedData[constants.EnvKeyJwtType].(string)
|
algo := updatedData[constants.EnvKeyJwtType].(string)
|
||||||
if params.JwtType != nil {
|
if params.JwtType != nil {
|
||||||
@@ -210,6 +265,8 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go clearSessionIfRequired(currentData, updatedData)
|
||||||
|
|
||||||
// Update local store
|
// Update local store
|
||||||
memorystore.Provider.UpdateEnvStore(updatedData)
|
memorystore.Provider.UpdateEnvStore(updatedData)
|
||||||
jwk, err := crypto.GenerateJWKBasedOnEnv()
|
jwk, err := crypto.GenerateJWKBasedOnEnv()
|
||||||
@@ -224,12 +281,6 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO check how to update session store based on env change.
|
|
||||||
// err = sessionstore.InitSession()
|
|
||||||
// if err != nil {
|
|
||||||
// log.Debug("Failed to init session store: ", err)
|
|
||||||
// return res, err
|
|
||||||
// }
|
|
||||||
err = oauth.InitOAuth()
|
err = oauth.InitOAuth()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
@@ -142,7 +142,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
|||||||
return res, fmt.Errorf("user with this email address already exists")
|
return res, fmt.Errorf("user with this email address already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
go memorystore.Provider.DeleteAllUserSession(user.ID)
|
go memorystore.Provider.DeleteAllUserSessions(user.ID)
|
||||||
go cookie.DeleteSession(gc)
|
go cookie.DeleteSession(gc)
|
||||||
|
|
||||||
user.Email = newEmail
|
user.Email = newEmail
|
||||||
|
@@ -113,7 +113,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO figure out how to do this
|
// TODO figure out how to do this
|
||||||
go memorystore.Provider.DeleteAllUserSession(user.ID)
|
go memorystore.Provider.DeleteAllUserSessions(user.ID)
|
||||||
|
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
user.Email = newEmail
|
user.Email = newEmail
|
||||||
@@ -182,7 +182,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
|||||||
rolesToSave = strings.Join(inputRoles, ",")
|
rolesToSave = strings.Join(inputRoles, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
go memorystore.Provider.DeleteAllUserSession(user.ID)
|
go memorystore.Provider.DeleteAllUserSessions(user.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rolesToSave != "" {
|
if rolesToSave != "" {
|
||||||
|
@@ -4,11 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/parsers"
|
"github.com/authorizerdev/authorizer/server/parsers"
|
||||||
@@ -30,48 +30,51 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken
|
|||||||
}
|
}
|
||||||
|
|
||||||
tokenType := params.TokenType
|
tokenType := params.TokenType
|
||||||
if tokenType != "access_token" && tokenType != "refresh_token" && tokenType != "id_token" {
|
if tokenType != constants.TokenTypeAccessToken && tokenType != constants.TokenTypeRefreshToken && tokenType != constants.TokenTypeIdentityToken {
|
||||||
log.Debug("Invalid token type: ", tokenType)
|
log.Debug("Invalid token type: ", tokenType)
|
||||||
return nil, errors.New("invalid token type")
|
return nil, errors.New("invalid token type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var claimRoles []string
|
||||||
|
var claims jwt.MapClaims
|
||||||
userID := ""
|
userID := ""
|
||||||
nonce := ""
|
nonce := ""
|
||||||
|
|
||||||
|
claims, err = token.ParseJWTToken(params.Token)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to parse JWT token: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userID = claims["sub"].(string)
|
||||||
|
|
||||||
// access_token and refresh_token should be validated from session store as well
|
// access_token and refresh_token should be validated from session store as well
|
||||||
if tokenType == "access_token" || tokenType == "refresh_token" {
|
if tokenType == constants.TokenTypeAccessToken || tokenType == constants.TokenTypeRefreshToken {
|
||||||
savedSession, err := memorystore.Provider.GetState(params.Token)
|
nonce = claims["nonce"].(string)
|
||||||
if savedSession == "" || err != nil {
|
loginMethod := claims["login_method"]
|
||||||
return &model.ValidateJWTTokenResponse{
|
sessionKey := userID
|
||||||
IsValid: false,
|
if loginMethod != nil && loginMethod != "" {
|
||||||
}, nil
|
sessionKey = loginMethod.(string) + ":" + userID
|
||||||
|
}
|
||||||
|
token, err := memorystore.Provider.GetUserSession(sessionKey, tokenType+"_"+claims["nonce"].(string))
|
||||||
|
if err != nil || token == "" {
|
||||||
|
log.Debug("Failed to get user session: ", err)
|
||||||
|
return nil, errors.New("invalid token")
|
||||||
}
|
}
|
||||||
savedSessionSplit := strings.Split(savedSession, "@")
|
|
||||||
nonce = savedSessionSplit[0]
|
|
||||||
userID = savedSessionSplit[1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
var claimRoles []string
|
|
||||||
var claims jwt.MapClaims
|
|
||||||
|
|
||||||
// we cannot validate sub and nonce in case of id_token as that token is not persisted in session store
|
// we cannot validate nonce in case of id_token as that token is not persisted in session store
|
||||||
if userID != "" && nonce != "" {
|
if nonce != "" {
|
||||||
claims, err = token.ParseJWTToken(params.Token, hostname, nonce, userID)
|
if ok, err := token.ValidateJWTClaims(claims, hostname, nonce, userID); !ok || err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to parse jwt token: ", err)
|
log.Debug("Failed to parse jwt token: ", err)
|
||||||
return &model.ValidateJWTTokenResponse{
|
return nil, errors.New("invalid claims")
|
||||||
IsValid: false,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
claims, err = token.ParseJWTTokenWithoutNonce(params.Token, hostname)
|
if ok, err := token.ValidateJWTTokenWithoutNonce(claims, hostname, userID); !ok || err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to parse jwt token without nonce: ", err)
|
log.Debug("Failed to parse jwt token without nonce: ", err)
|
||||||
return &model.ValidateJWTTokenResponse{
|
return nil, errors.New("invalid claims")
|
||||||
IsValid: false,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
claimRolesInterface := claims["roles"]
|
claimRolesInterface := claims["roles"]
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
@@ -36,12 +37,17 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
|
|||||||
|
|
||||||
// verify if token exists in db
|
// verify if token exists in db
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email)
|
claim, err := token.ParseJWTToken(params.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to parse token: ", err)
|
log.Debug("Failed to parse token: ", err)
|
||||||
return res, fmt.Errorf(`invalid token: %s`, err.Error())
|
return res, fmt.Errorf(`invalid token: %s`, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ok, err := token.ValidateJWTClaims(claim, hostname, verificationRequest.Nonce, verificationRequest.Email); !ok || err != nil {
|
||||||
|
log.Debug("Failed to validate jwt claims: ", err)
|
||||||
|
return res, fmt.Errorf(`invalid token: %s`, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
email := claim["sub"].(string)
|
email := claim["sub"].(string)
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"email": email,
|
"email": email,
|
||||||
@@ -67,17 +73,19 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loginMethod := constants.AuthRecipeMethodBasicAuth
|
||||||
|
if loginMethod == constants.VerificationTypeMagicLinkLogin {
|
||||||
|
loginMethod = constants.AuthRecipeMethodMagicLinkLogin
|
||||||
|
}
|
||||||
|
|
||||||
roles := strings.Split(user.Roles, ",")
|
roles := strings.Split(user.Roles, ",")
|
||||||
scope := []string{"openid", "email", "profile"}
|
scope := []string{"openid", "email", "profile"}
|
||||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to create auth token: ", err)
|
log.Debug("Failed to create auth token: ", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
UserAgent: utils.GetUserAgent(gc.Request),
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
@@ -96,5 +104,15 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
|
|||||||
ExpiresIn: &expiresIn,
|
ExpiresIn: &expiresIn,
|
||||||
User: user.AsAPIUser(),
|
User: user.AsAPIUser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionKey := loginMethod + ":" + user.ID
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ func InitRouter(log *logrus.Logger) *gin.Engine {
|
|||||||
router.GET("/playground", handlers.PlaygroundHandler())
|
router.GET("/playground", handlers.PlaygroundHandler())
|
||||||
router.GET("/oauth_login/:oauth_provider", handlers.OAuthLoginHandler())
|
router.GET("/oauth_login/:oauth_provider", handlers.OAuthLoginHandler())
|
||||||
router.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
|
router.GET("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
|
||||||
|
router.POST("/oauth_callback/:oauth_provider", handlers.OAuthCallbackHandler())
|
||||||
router.GET("/verify_email", handlers.VerifyEmailHandler())
|
router.GET("/verify_email", handlers.VerifyEmailHandler())
|
||||||
// OPEN ID routes
|
// OPEN ID routes
|
||||||
router.GET("/.well-known/openid-configuration", handlers.OpenIDConfigurationHandler())
|
router.GET("/.well-known/openid-configuration", handlers.OpenIDConfigurationHandler())
|
||||||
|
@@ -52,7 +52,7 @@ func TestJwt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
jwtToken, err := token.SignJWTToken(expiredClaims)
|
jwtToken, err := token.SignJWTToken(expiredClaims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
_, err = token.ParseJWTToken(jwtToken)
|
||||||
assert.Error(t, err, err.Error(), "Token is expired")
|
assert.Error(t, err, err.Error(), "Token is expired")
|
||||||
})
|
})
|
||||||
t.Run("HMAC algorithms", func(t *testing.T) {
|
t.Run("HMAC algorithms", func(t *testing.T) {
|
||||||
@@ -62,27 +62,36 @@ func TestJwt(t *testing.T) {
|
|||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
t.Run("HS384", func(t *testing.T) {
|
t.Run("HS384", func(t *testing.T) {
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS384")
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS384")
|
||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
t.Run("HS512", func(t *testing.T) {
|
t.Run("HS512", func(t *testing.T) {
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS512")
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJwtType, "HS512")
|
||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -96,9 +105,12 @@ func TestJwt(t *testing.T) {
|
|||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
t.Run("RS384", func(t *testing.T) {
|
t.Run("RS384", func(t *testing.T) {
|
||||||
_, privateKey, publickKey, _, err := crypto.NewRSAKey("RS384", clientID)
|
_, privateKey, publickKey, _, err := crypto.NewRSAKey("RS384", clientID)
|
||||||
@@ -109,9 +121,12 @@ func TestJwt(t *testing.T) {
|
|||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
t.Run("RS512", func(t *testing.T) {
|
t.Run("RS512", func(t *testing.T) {
|
||||||
_, privateKey, publickKey, _, err := crypto.NewRSAKey("RS512", clientID)
|
_, privateKey, publickKey, _, err := crypto.NewRSAKey("RS512", clientID)
|
||||||
@@ -122,9 +137,12 @@ func TestJwt(t *testing.T) {
|
|||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -138,9 +156,12 @@ func TestJwt(t *testing.T) {
|
|||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
t.Run("ES384", func(t *testing.T) {
|
t.Run("ES384", func(t *testing.T) {
|
||||||
_, privateKey, publickKey, _, err := crypto.NewECDSAKey("ES384", clientID)
|
_, privateKey, publickKey, _, err := crypto.NewECDSAKey("ES384", clientID)
|
||||||
@@ -151,9 +172,12 @@ func TestJwt(t *testing.T) {
|
|||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
t.Run("ES512", func(t *testing.T) {
|
t.Run("ES512", func(t *testing.T) {
|
||||||
_, privateKey, publickKey, _, err := crypto.NewECDSAKey("ES512", clientID)
|
_, privateKey, publickKey, _, err := crypto.NewECDSAKey("ES512", clientID)
|
||||||
@@ -164,9 +188,12 @@ func TestJwt(t *testing.T) {
|
|||||||
jwtToken, err := token.SignJWTToken(claims)
|
jwtToken, err := token.SignJWTToken(claims)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, jwtToken)
|
assert.NotEmpty(t, jwtToken)
|
||||||
c, err := token.ParseJWTToken(jwtToken, hostname, nonce, subject)
|
c, err := token.ParseJWTToken(jwtToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, c["email"].(string), claims["email"])
|
assert.Equal(t, c["email"].(string), claims["email"])
|
||||||
|
valid, err := token.ValidateJWTClaims(c, hostname, nonce, subject)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, valid)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ package test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
@@ -9,6 +10,7 @@ import (
|
|||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,16 +29,26 @@ func logoutTests(t *testing.T, s TestSetup) {
|
|||||||
Token: verificationRequest.Token,
|
Token: verificationRequest.Token,
|
||||||
})
|
})
|
||||||
|
|
||||||
token := *verifyRes.AccessToken
|
accessToken := *verifyRes.AccessToken
|
||||||
sessions := memorystore.Provider.GetUserSessions(verifyRes.User.ID)
|
assert.NotEmpty(t, accessToken)
|
||||||
cookie := ""
|
|
||||||
// set all they keys in cookie one of them should be session cookie
|
claims, err := token.ParseJWTToken(accessToken)
|
||||||
for key := range sessions {
|
assert.NoError(t, err)
|
||||||
if key != token {
|
assert.NotEmpty(t, claims)
|
||||||
cookie += fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", key)
|
|
||||||
}
|
loginMethod := claims["login_method"]
|
||||||
|
sessionKey := verifyRes.User.ID
|
||||||
|
if loginMethod != nil && loginMethod != "" {
|
||||||
|
sessionKey = loginMethod.(string) + ":" + verifyRes.User.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, sessionToken)
|
||||||
|
|
||||||
|
cookie := fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken)
|
||||||
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
|
||||||
req.Header.Set("Cookie", cookie)
|
req.Header.Set("Cookie", cookie)
|
||||||
_, err = resolvers.LogoutResolver(ctx)
|
_, err = resolvers.LogoutResolver(ctx)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
@@ -37,9 +37,9 @@ func profileTests(t *testing.T, s TestSetup) {
|
|||||||
ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext)
|
ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext)
|
||||||
profileRes, err := resolvers.ProfileResolver(ctx)
|
profileRes, err := resolvers.ProfileResolver(ctx)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, profileRes)
|
||||||
s.GinContext.Request.Header.Set("Authorization", "")
|
s.GinContext.Request.Header.Set("Authorization", "")
|
||||||
|
newEmail := profileRes.Email
|
||||||
newEmail := *&profileRes.Email
|
|
||||||
assert.Equal(t, email, newEmail, "emails should be equal")
|
assert.Equal(t, email, newEmail, "emails should be equal")
|
||||||
|
|
||||||
cleanData(email)
|
cleanData(email)
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,19 +34,22 @@ func sessionTests(t *testing.T, s TestSetup) {
|
|||||||
Token: verificationRequest.Token,
|
Token: verificationRequest.Token,
|
||||||
})
|
})
|
||||||
|
|
||||||
sessions := memorystore.Provider.GetUserSessions(verifyRes.User.ID)
|
accessToken := *verifyRes.AccessToken
|
||||||
cookie := ""
|
assert.NotEmpty(t, accessToken)
|
||||||
token := *verifyRes.AccessToken
|
|
||||||
// set all they keys in cookie one of them should be session cookie
|
claims, err := token.ParseJWTToken(accessToken)
|
||||||
for key := range sessions {
|
assert.NoError(t, err)
|
||||||
if key != token {
|
assert.NotEmpty(t, claims)
|
||||||
cookie += fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", key)
|
|
||||||
}
|
sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + verifyRes.User.ID
|
||||||
}
|
sessionToken, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, sessionToken)
|
||||||
|
|
||||||
|
cookie := fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken)
|
||||||
cookie = strings.TrimSuffix(cookie, ";")
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
|
||||||
req.Header.Set("Cookie", cookie)
|
req.Header.Set("Cookie", cookie)
|
||||||
|
|
||||||
_, err = resolvers.SessionResolver(ctx, &model.SessionQueryInput{})
|
_, err = resolvers.SessionResolver(ctx, &model.SessionQueryInput{})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
@@ -22,12 +23,14 @@ func validateJwtTokenTest(t *testing.T, s TestSetup) {
|
|||||||
TokenType: "access_token",
|
TokenType: "access_token",
|
||||||
Token: "",
|
Token: "",
|
||||||
})
|
})
|
||||||
assert.False(t, res.IsValid)
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
res, err = resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
res, err = resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
||||||
TokenType: "access_token",
|
TokenType: "access_token",
|
||||||
Token: "invalid",
|
Token: "invalid",
|
||||||
})
|
})
|
||||||
assert.False(t, res.IsValid)
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
_, err = resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
_, err = resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
||||||
TokenType: "access_token_invalid",
|
TokenType: "access_token_invalid",
|
||||||
Token: "invalid@invalid",
|
Token: "invalid@invalid",
|
||||||
@@ -47,9 +50,14 @@ func validateJwtTokenTest(t *testing.T, s TestSetup) {
|
|||||||
roles := []string{"user"}
|
roles := []string{"user"}
|
||||||
gc, err := utils.GinContextFromContext(ctx)
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID
|
||||||
memorystore.Provider.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth)
|
||||||
memorystore.Provider.SetState(authToken.RefreshToken.Token, authToken.FingerPrint+"@"+user.ID)
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
|
|
||||||
t.Run(`should validate the access token`, func(t *testing.T) {
|
t.Run(`should validate the access token`, func(t *testing.T) {
|
||||||
res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
||||||
@@ -57,7 +65,6 @@ func validateJwtTokenTest(t *testing.T, s TestSetup) {
|
|||||||
Token: authToken.AccessToken.Token,
|
Token: authToken.AccessToken.Token,
|
||||||
Roles: []string{"user"},
|
Roles: []string{"user"},
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, res.IsValid)
|
assert.True(t, res.IsValid)
|
||||||
|
|
||||||
|
@@ -43,9 +43,9 @@ func TestIsValidIdentifier(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsValidPassword(t *testing.T) {
|
func TestIsValidPassword(t *testing.T) {
|
||||||
assert.False(t, validators.IsValidPassword("test"), "it should be invalid password")
|
assert.Error(t, validators.IsValidPassword("test"), "it should be invalid password")
|
||||||
assert.False(t, validators.IsValidPassword("Te@1"), "it should be invalid password")
|
assert.Error(t, validators.IsValidPassword("Te@1"), "it should be invalid password")
|
||||||
assert.False(t, validators.IsValidPassword("n*rp7GGTd29V{xx%{pDb@7n{](SD.!+.Mp#*$EHDGk&$pAMf7e#432Sg,Gr](j3n]jV/3F8BJJT+9u9{q=8zK:8u!rpQBaXJp%A+7r!jQj)M(vC$UX,h;;WKm$U6i#7dBnC&2ryKzKd+(y&=Ud)hErT/j;v3t..CM).8nS)9qLtV7pmP;@2QuzDyGfL7KB()k:BpjAGL@bxD%r5gcBfh7$&wutk!wzMfPFY#nkjjqyZbEHku,{jc;gvbYq2)3w=KExnYz9Vbv:;*;?f##faxkULdMpmm&yEfePixzx+[{[38zGN;3TzF;6M#Xy_tMtx:yK*n$bc(bPyGz%EYkC&]ttUF@#aZ%$QZ:u!icF@+"), "it should be invalid password")
|
assert.Error(t, validators.IsValidPassword("n*rp7GGTd29V{xx%{pDb@7n{](SD.!+.Mp#*$EHDGk&$pAMf7e#432Sg,Gr](j3n]jV/3F8BJJT+9u9{q=8zK:8u!rpQBaXJp%A+7r!jQj)M(vC$UX,h;;WKm$U6i#7dBnC&2ryKzKd+(y&=Ud)hErT/j;v3t..CM).8nS)9qLtV7pmP;@2QuzDyGfL7KB()k:BpjAGL@bxD%r5gcBfh7$&wutk!wzMfPFY#nkjjqyZbEHku,{jc;gvbYq2)3w=KExnYz9Vbv:;*;?f##faxkULdMpmm&yEfePixzx+[{[38zGN;3TzF;6M#Xy_tMtx:yK*n$bc(bPyGz%EYkC&]ttUF@#aZ%$QZ:u!icF@+"), "it should be invalid password")
|
||||||
assert.False(t, validators.IsValidPassword("test@123"), "it should be invalid password")
|
assert.Error(t, validators.IsValidPassword("test@123"), "it should be invalid password")
|
||||||
assert.True(t, validators.IsValidPassword("Test@123"), "it should be valid password")
|
assert.NoError(t, validators.IsValidPassword("Test@123"), "it should be valid password")
|
||||||
}
|
}
|
||||||
|
@@ -38,23 +38,25 @@ type Token struct {
|
|||||||
|
|
||||||
// SessionData
|
// SessionData
|
||||||
type SessionData struct {
|
type SessionData struct {
|
||||||
Subject string `json:"sub"`
|
Subject string `json:"sub"`
|
||||||
Roles []string `json:"roles"`
|
Roles []string `json:"roles"`
|
||||||
Scope []string `json:"scope"`
|
Scope []string `json:"scope"`
|
||||||
Nonce string `json:"nonce"`
|
Nonce string `json:"nonce"`
|
||||||
IssuedAt int64 `json:"iat"`
|
IssuedAt int64 `json:"iat"`
|
||||||
ExpiresAt int64 `json:"exp"`
|
ExpiresAt int64 `json:"exp"`
|
||||||
|
LoginMethod string `json:"login_method"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSessionToken creates a new session token
|
// CreateSessionToken creates a new session token
|
||||||
func CreateSessionToken(user models.User, nonce string, roles, scope []string) (*SessionData, string, error) {
|
func CreateSessionToken(user models.User, nonce string, roles, scope []string, loginMethod string) (*SessionData, string, error) {
|
||||||
fingerPrintMap := &SessionData{
|
fingerPrintMap := &SessionData{
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
Roles: roles,
|
Roles: roles,
|
||||||
Subject: user.ID,
|
Subject: user.ID,
|
||||||
Scope: scope,
|
Scope: scope,
|
||||||
IssuedAt: time.Now().Unix(),
|
LoginMethod: loginMethod,
|
||||||
ExpiresAt: time.Now().AddDate(1, 0, 0).Unix(),
|
IssuedAt: time.Now().Unix(),
|
||||||
|
ExpiresAt: time.Now().AddDate(1, 0, 0).Unix(),
|
||||||
}
|
}
|
||||||
fingerPrintBytes, _ := json.Marshal(fingerPrintMap)
|
fingerPrintBytes, _ := json.Marshal(fingerPrintMap)
|
||||||
fingerPrintHash, err := crypto.EncryptAES(string(fingerPrintBytes))
|
fingerPrintHash, err := crypto.EncryptAES(string(fingerPrintBytes))
|
||||||
@@ -66,19 +68,19 @@ func CreateSessionToken(user models.User, nonce string, roles, scope []string) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateAuthToken creates a new auth token when userlogs in
|
// CreateAuthToken creates a new auth token when userlogs in
|
||||||
func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string) (*Token, error) {
|
func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string, loginMethod string) (*Token, error) {
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
nonce := uuid.New().String()
|
nonce := uuid.New().String()
|
||||||
_, fingerPrintHash, err := CreateSessionToken(user, nonce, roles, scope)
|
_, fingerPrintHash, err := CreateSessionToken(user, nonce, roles, scope, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
accessToken, accessTokenExpiresAt, err := CreateAccessToken(user, roles, scope, hostname, nonce)
|
accessToken, accessTokenExpiresAt, err := CreateAccessToken(user, roles, scope, hostname, nonce, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
idToken, idTokenExpiresAt, err := CreateIDToken(user, roles, hostname, nonce)
|
idToken, idTokenExpiresAt, err := CreateIDToken(user, roles, hostname, nonce, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -91,7 +93,7 @@ func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if utils.StringSliceContains(scope, "offline_access") {
|
if utils.StringSliceContains(scope, "offline_access") {
|
||||||
refreshToken, refreshTokenExpiresAt, err := CreateRefreshToken(user, roles, scope, hostname, nonce)
|
refreshToken, refreshTokenExpiresAt, err := CreateRefreshToken(user, roles, scope, hostname, nonce, loginMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -103,7 +105,7 @@ func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateRefreshToken util to create JWT token
|
// CreateRefreshToken util to create JWT token
|
||||||
func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonce string) (string, int64, error) {
|
func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonce, loginMethod string) (string, int64, error) {
|
||||||
// expires in 1 year
|
// expires in 1 year
|
||||||
expiryBound := time.Hour * 8760
|
expiryBound := time.Hour * 8760
|
||||||
expiresAt := time.Now().Add(expiryBound).Unix()
|
expiresAt := time.Now().Add(expiryBound).Unix()
|
||||||
@@ -112,15 +114,16 @@ func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonc
|
|||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
customClaims := jwt.MapClaims{
|
customClaims := jwt.MapClaims{
|
||||||
"iss": hostname,
|
"iss": hostname,
|
||||||
"aud": clientID,
|
"aud": clientID,
|
||||||
"sub": user.ID,
|
"sub": user.ID,
|
||||||
"exp": expiresAt,
|
"exp": expiresAt,
|
||||||
"iat": time.Now().Unix(),
|
"iat": time.Now().Unix(),
|
||||||
"token_type": constants.TokenTypeRefreshToken,
|
"token_type": constants.TokenTypeRefreshToken,
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
"scope": scopes,
|
"scope": scopes,
|
||||||
"nonce": nonce,
|
"nonce": nonce,
|
||||||
|
"login_method": loginMethod,
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := SignJWTToken(customClaims)
|
token, err := SignJWTToken(customClaims)
|
||||||
@@ -133,7 +136,7 @@ func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonc
|
|||||||
|
|
||||||
// CreateAccessToken util to create JWT token, based on
|
// CreateAccessToken util to create JWT token, based on
|
||||||
// user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT
|
// user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT
|
||||||
func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce string) (string, int64, error) {
|
func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce, loginMethod string) (string, int64, error) {
|
||||||
expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime)
|
expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
@@ -150,15 +153,16 @@ func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce
|
|||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
customClaims := jwt.MapClaims{
|
customClaims := jwt.MapClaims{
|
||||||
"iss": hostName,
|
"iss": hostName,
|
||||||
"aud": clientID,
|
"aud": clientID,
|
||||||
"nonce": nonce,
|
"nonce": nonce,
|
||||||
"sub": user.ID,
|
"sub": user.ID,
|
||||||
"exp": expiresAt,
|
"exp": expiresAt,
|
||||||
"iat": time.Now().Unix(),
|
"iat": time.Now().Unix(),
|
||||||
"token_type": constants.TokenTypeAccessToken,
|
"token_type": constants.TokenTypeAccessToken,
|
||||||
"scope": scopes,
|
"scope": scopes,
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
|
"login_method": loginMethod,
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := SignJWTToken(customClaims)
|
token, err := SignJWTToken(customClaims)
|
||||||
@@ -198,18 +202,30 @@ func ValidateAccessToken(gc *gin.Context, accessToken string) (map[string]interf
|
|||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
savedSession, err := memorystore.Provider.GetState(accessToken)
|
res, err := ParseJWTToken(accessToken)
|
||||||
if savedSession == "" || err != nil {
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := res["sub"].(string)
|
||||||
|
nonce := res["nonce"].(string)
|
||||||
|
loginMethod := res["login_method"]
|
||||||
|
sessionKey := userID
|
||||||
|
if loginMethod != nil && loginMethod != "" {
|
||||||
|
sessionKey = loginMethod.(string) + ":" + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce)
|
||||||
|
if nonce == "" || err != nil {
|
||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
savedSessionSplit := strings.Split(savedSession, "@")
|
if token != accessToken {
|
||||||
nonce := savedSessionSplit[0]
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
userID := savedSessionSplit[1]
|
}
|
||||||
|
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
res, err = ParseJWTToken(accessToken, hostname, nonce, userID)
|
if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil {
|
||||||
if err != nil {
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,18 +244,30 @@ func ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]inte
|
|||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
savedSession, err := memorystore.Provider.GetState(refreshToken)
|
res, err := ParseJWTToken(refreshToken)
|
||||||
if savedSession == "" || err != nil {
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := res["sub"].(string)
|
||||||
|
nonce := res["nonce"].(string)
|
||||||
|
loginMethod := res["login_method"]
|
||||||
|
sessionKey := userID
|
||||||
|
if loginMethod != nil && loginMethod != "" {
|
||||||
|
sessionKey = loginMethod.(string) + ":" + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+nonce)
|
||||||
|
if nonce == "" || err != nil {
|
||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
savedSessionSplit := strings.Split(savedSession, "@")
|
if token != refreshToken {
|
||||||
nonce := savedSessionSplit[0]
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
userID := savedSessionSplit[1]
|
}
|
||||||
|
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
res, err = ParseJWTToken(refreshToken, hostname, nonce, userID)
|
if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil {
|
||||||
if err != nil {
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,15 +283,6 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD
|
|||||||
return nil, fmt.Errorf(`unauthorized`)
|
return nil, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
savedSession, err := memorystore.Provider.GetState(encryptedSession)
|
|
||||||
if savedSession == "" || err != nil {
|
|
||||||
return nil, fmt.Errorf(`unauthorized`)
|
|
||||||
}
|
|
||||||
|
|
||||||
savedSessionSplit := strings.Split(savedSession, "@")
|
|
||||||
nonce := savedSessionSplit[0]
|
|
||||||
userID := savedSessionSplit[1]
|
|
||||||
|
|
||||||
decryptedFingerPrint, err := crypto.DecryptAES(encryptedSession)
|
decryptedFingerPrint, err := crypto.DecryptAES(encryptedSession)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -275,29 +294,31 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.Nonce != nonce {
|
sessionStoreKey := res.Subject
|
||||||
return nil, fmt.Errorf(`unauthorized: invalid nonce`)
|
if res.LoginMethod != "" {
|
||||||
|
sessionStoreKey = res.LoginMethod + ":" + res.Subject
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.Subject != userID {
|
token, err := memorystore.Provider.GetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+res.Nonce)
|
||||||
return nil, fmt.Errorf(`unauthorized: invalid user id`)
|
if token == "" || err != nil {
|
||||||
|
log.Debug("invalid browser session:", err)
|
||||||
|
return nil, fmt.Errorf(`unauthorized`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if encryptedSession != token {
|
||||||
|
return nil, fmt.Errorf(`unauthorized: invalid nonce`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.ExpiresAt < time.Now().Unix() {
|
if res.ExpiresAt < time.Now().Unix() {
|
||||||
return nil, fmt.Errorf(`unauthorized: token expired`)
|
return nil, fmt.Errorf(`unauthorized: token expired`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO validate scope
|
|
||||||
// if !reflect.DeepEqual(res.Roles, roles) {
|
|
||||||
// return res, "", fmt.Errorf(`unauthorized`)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIDToken util to create JWT token, based on
|
// CreateIDToken util to create JWT token, based on
|
||||||
// user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT
|
// user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT
|
||||||
func CreateIDToken(user models.User, roles []string, hostname, nonce string) (string, int64, error) {
|
func CreateIDToken(user models.User, roles []string, hostname, nonce, loginMethod string) (string, int64, error) {
|
||||||
expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime)
|
expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
@@ -332,6 +353,7 @@ func CreateIDToken(user models.User, roles []string, hostname, nonce string) (st
|
|||||||
"iat": time.Now().Unix(),
|
"iat": time.Now().Unix(),
|
||||||
"token_type": constants.TokenTypeIdentityToken,
|
"token_type": constants.TokenTypeIdentityToken,
|
||||||
"allowed_roles": strings.Split(user.Roles, ","),
|
"allowed_roles": strings.Split(user.Roles, ","),
|
||||||
|
"login_method": loginMethod,
|
||||||
claimKey: roles,
|
claimKey: roles,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,10 +3,11 @@ package token
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/golang-jwt/jwt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignJWTToken common util to sing jwt token
|
// SignJWTToken common util to sing jwt token
|
||||||
@@ -59,7 +60,7 @@ func SignJWTToken(claims jwt.MapClaims) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseJWTToken common util to parse jwt token
|
// ParseJWTToken common util to parse jwt token
|
||||||
func ParseJWTToken(token, hostname, nonce, subject string) (jwt.MapClaims, error) {
|
func ParseJWTToken(token string) (jwt.MapClaims, error) {
|
||||||
jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -115,98 +116,51 @@ func ParseJWTToken(token, hostname, nonce, subject string) (jwt.MapClaims, error
|
|||||||
intIat := int64(claims["iat"].(float64))
|
intIat := int64(claims["iat"].(float64))
|
||||||
claims["exp"] = intExp
|
claims["exp"] = intExp
|
||||||
claims["iat"] = intIat
|
claims["iat"] = intIat
|
||||||
|
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateJWTClaims common util to validate claims
|
||||||
|
func ValidateJWTClaims(claims jwt.MapClaims, hostname, nonce, subject string) (bool, error) {
|
||||||
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return claims, err
|
return false, err
|
||||||
}
|
}
|
||||||
if claims["aud"] != clientID {
|
if claims["aud"] != clientID {
|
||||||
return claims, errors.New("invalid audience")
|
return false, errors.New("invalid audience")
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims["nonce"] != nonce {
|
if claims["nonce"] != nonce {
|
||||||
return claims, errors.New("invalid nonce")
|
return false, errors.New("invalid nonce")
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims["iss"] != hostname {
|
if claims["iss"] != hostname {
|
||||||
return claims, errors.New("invalid issuer")
|
return false, errors.New("invalid issuer")
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims["sub"] != subject {
|
if claims["sub"] != subject {
|
||||||
return claims, errors.New("invalid subject")
|
return false, errors.New("invalid subject")
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseJWTTokenWithoutNonce common util to parse jwt token without nonce
|
// ValidateJWTTokenWithoutNonce common util to validate claims without nonce
|
||||||
// used to validate ID token as it is not persisted in store
|
func ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, hostname, subject string) (bool, error) {
|
||||||
func ParseJWTTokenWithoutNonce(token, hostname string) (jwt.MapClaims, error) {
|
|
||||||
jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
signingMethod := jwt.GetSigningMethod(jwtType)
|
|
||||||
|
|
||||||
var claims jwt.MapClaims
|
|
||||||
|
|
||||||
switch signingMethod {
|
|
||||||
case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512:
|
|
||||||
_, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
jwtSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return []byte(jwtSecret), nil
|
|
||||||
})
|
|
||||||
case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512:
|
|
||||||
_, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
key, err := crypto.ParseRsaPublicKeyFromPemStr(jwtPublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return key, nil
|
|
||||||
})
|
|
||||||
case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512:
|
|
||||||
_, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
key, err := crypto.ParseEcdsaPublicKeyFromPemStr(jwtPublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return key, nil
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
err = errors.New("unsupported signing method")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return claims, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// claim parses exp & iat into float 64 with e^10,
|
|
||||||
// but we expect it to be int64
|
|
||||||
// hence we need to assert interface and convert to int64
|
|
||||||
intExp := int64(claims["exp"].(float64))
|
|
||||||
intIat := int64(claims["iat"].(float64))
|
|
||||||
claims["exp"] = intExp
|
|
||||||
claims["iat"] = intIat
|
|
||||||
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return claims, err
|
return false, err
|
||||||
}
|
}
|
||||||
if claims["aud"] != clientID {
|
if claims["aud"] != clientID {
|
||||||
return claims, errors.New("invalid audience")
|
return false, errors.New("invalid audience")
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims["iss"] != hostname {
|
if claims["iss"] != hostname {
|
||||||
return claims, errors.New("invalid issuer")
|
return false, errors.New("invalid issuer")
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims, nil
|
if claims["sub"] != subject {
|
||||||
|
return false, errors.New("invalid subject")
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
package validators
|
package validators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
)
|
||||||
|
|
||||||
// ValidatePassword to validate the password against the following policy
|
// ValidatePassword to validate the password against the following policy
|
||||||
// min char length: 6
|
// min char length: 6
|
||||||
// max char length: 36
|
// max char length: 36
|
||||||
@@ -7,9 +14,16 @@ package validators
|
|||||||
// at least one lower case letter
|
// at least one lower case letter
|
||||||
// at least one digit
|
// at least one digit
|
||||||
// at least one special character
|
// at least one special character
|
||||||
func IsValidPassword(password string) bool {
|
func IsValidPassword(password string) error {
|
||||||
if len(password) < 6 || len(password) > 36 {
|
if len(password) < 6 || len(password) > 36 {
|
||||||
return false
|
return errors.New("password must be of minimum 6 characters and maximum 36 characters")
|
||||||
|
}
|
||||||
|
|
||||||
|
// if strong password is disabled
|
||||||
|
// just check for min 6 chars & max 36
|
||||||
|
isStrongPasswordDisabled, _ := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableStrongPassword)
|
||||||
|
if isStrongPasswordDisabled {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
hasUpperCase := false
|
hasUpperCase := false
|
||||||
@@ -29,5 +43,11 @@ func IsValidPassword(password string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar
|
isValid := hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar
|
||||||
|
|
||||||
|
if isValid {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user