You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

login_source.go 24 kB

11 years ago
11 years ago
11 years ago
4 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Add single sign-on support via SSPI on Windows (#8463) * Add single sign-on support via SSPI on Windows * Ensure plugins implement interface * Ensure plugins implement interface * Move functions used only by the SSPI auth method to sspi_windows.go * Field SSPISeparatorReplacement of AuthenticationForm should not be required via binding, as binding will insist the field is non-empty even if another login type is selected * Fix breaking of oauth authentication on download links. Do not create new session with SSPI authentication on download links. * Update documentation for the new 'SPNEGO with SSPI' login source * Mention in documentation that ROOT_URL should contain the FQDN of the server * Make sure that Contexter is not checking for active login sources when the ORM engine is not initialized (eg. when installing) * Always initialize and free SSO methods, even if they are not enabled, as a method can be activated while the app is running (from Authentication sources) * Add option in SSPIConfig for removing of domains from logon names * Update helper text for StripDomainNames option * Make sure handleSignIn() is called after a new user object is created by SSPI auth method * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Only make a query to the DB to check if SSPI is enabled on handlers that need that information for templates * Remove code duplication * Log errors in ActiveLoginSources Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert suffix of randomly generated E-mails for Reverse proxy authentication Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert unneeded white-space change in template Co-Authored-By: Lauris BH <lauris@nix.lv> * Add copyright comments at the top of new files * Use loopback name for randomly generated emails * Add locale tag for the SSPISeparatorReplacement field with proper casing * Revert casing of SSPISeparatorReplacement field in locale file, moving it up, next to other form fields * Update docs/content/doc/features/authentication.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Remove Priority() method and define the order in which SSO auth methods should be executed in one place * Log authenticated username only if it's not empty * Rephrase helper text for automatic creation of users * Return error if more than one active SSPI auth source is found * Change newUser() function to return error, letting caller log/handle the error * Move isPublicResource, isPublicPage and handleSignIn functions outside SSPI auth method to allow other SSO methods to reuse them if needed * Refactor initialization of the list containing SSO auth methods * Validate SSPI settings on POST * Change SSPI to only perform authentication on its own login page, API paths and download links. Leave Toggle middleware to redirect non authenticated users to login page * Make 'Default language' in SSPI config empty, unless changed by admin * Show error if admin tries to add a second authentication source of type SSPI * Simplify declaration of global variable * Rebuild gitgraph.js on Linux * Make sure config values containing only whitespace are not accepted
5 years ago
11 years ago
11 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Add single sign-on support via SSPI on Windows (#8463) * Add single sign-on support via SSPI on Windows * Ensure plugins implement interface * Ensure plugins implement interface * Move functions used only by the SSPI auth method to sspi_windows.go * Field SSPISeparatorReplacement of AuthenticationForm should not be required via binding, as binding will insist the field is non-empty even if another login type is selected * Fix breaking of oauth authentication on download links. Do not create new session with SSPI authentication on download links. * Update documentation for the new 'SPNEGO with SSPI' login source * Mention in documentation that ROOT_URL should contain the FQDN of the server * Make sure that Contexter is not checking for active login sources when the ORM engine is not initialized (eg. when installing) * Always initialize and free SSO methods, even if they are not enabled, as a method can be activated while the app is running (from Authentication sources) * Add option in SSPIConfig for removing of domains from logon names * Update helper text for StripDomainNames option * Make sure handleSignIn() is called after a new user object is created by SSPI auth method * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Only make a query to the DB to check if SSPI is enabled on handlers that need that information for templates * Remove code duplication * Log errors in ActiveLoginSources Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert suffix of randomly generated E-mails for Reverse proxy authentication Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert unneeded white-space change in template Co-Authored-By: Lauris BH <lauris@nix.lv> * Add copyright comments at the top of new files * Use loopback name for randomly generated emails * Add locale tag for the SSPISeparatorReplacement field with proper casing * Revert casing of SSPISeparatorReplacement field in locale file, moving it up, next to other form fields * Update docs/content/doc/features/authentication.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Remove Priority() method and define the order in which SSO auth methods should be executed in one place * Log authenticated username only if it's not empty * Rephrase helper text for automatic creation of users * Return error if more than one active SSPI auth source is found * Change newUser() function to return error, letting caller log/handle the error * Move isPublicResource, isPublicPage and handleSignIn functions outside SSPI auth method to allow other SSO methods to reuse them if needed * Refactor initialization of the list containing SSO auth methods * Validate SSPI settings on POST * Change SSPI to only perform authentication on its own login page, API paths and download links. Leave Toggle middleware to redirect non authenticated users to login page * Make 'Default language' in SSPI config empty, unless changed by admin * Show error if admin tries to add a second authentication source of type SSPI * Simplify declaration of global variable * Rebuild gitgraph.js on Linux * Make sure config values containing only whitespace are not accepted
5 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Add single sign-on support via SSPI on Windows (#8463) * Add single sign-on support via SSPI on Windows * Ensure plugins implement interface * Ensure plugins implement interface * Move functions used only by the SSPI auth method to sspi_windows.go * Field SSPISeparatorReplacement of AuthenticationForm should not be required via binding, as binding will insist the field is non-empty even if another login type is selected * Fix breaking of oauth authentication on download links. Do not create new session with SSPI authentication on download links. * Update documentation for the new 'SPNEGO with SSPI' login source * Mention in documentation that ROOT_URL should contain the FQDN of the server * Make sure that Contexter is not checking for active login sources when the ORM engine is not initialized (eg. when installing) * Always initialize and free SSO methods, even if they are not enabled, as a method can be activated while the app is running (from Authentication sources) * Add option in SSPIConfig for removing of domains from logon names * Update helper text for StripDomainNames option * Make sure handleSignIn() is called after a new user object is created by SSPI auth method * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Only make a query to the DB to check if SSPI is enabled on handlers that need that information for templates * Remove code duplication * Log errors in ActiveLoginSources Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert suffix of randomly generated E-mails for Reverse proxy authentication Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert unneeded white-space change in template Co-Authored-By: Lauris BH <lauris@nix.lv> * Add copyright comments at the top of new files * Use loopback name for randomly generated emails * Add locale tag for the SSPISeparatorReplacement field with proper casing * Revert casing of SSPISeparatorReplacement field in locale file, moving it up, next to other form fields * Update docs/content/doc/features/authentication.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Remove Priority() method and define the order in which SSO auth methods should be executed in one place * Log authenticated username only if it's not empty * Rephrase helper text for automatic creation of users * Return error if more than one active SSPI auth source is found * Change newUser() function to return error, letting caller log/handle the error * Move isPublicResource, isPublicPage and handleSignIn functions outside SSPI auth method to allow other SSO methods to reuse them if needed * Refactor initialization of the list containing SSO auth methods * Validate SSPI settings on POST * Change SSPI to only perform authentication on its own login page, API paths and download links. Leave Toggle middleware to redirect non authenticated users to login page * Make 'Default language' in SSPI config empty, unless changed by admin * Show error if admin tries to add a second authentication source of type SSPI * Simplify declaration of global variable * Rebuild gitgraph.js on Linux * Make sure config values containing only whitespace are not accepted
5 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Add single sign-on support via SSPI on Windows (#8463) * Add single sign-on support via SSPI on Windows * Ensure plugins implement interface * Ensure plugins implement interface * Move functions used only by the SSPI auth method to sspi_windows.go * Field SSPISeparatorReplacement of AuthenticationForm should not be required via binding, as binding will insist the field is non-empty even if another login type is selected * Fix breaking of oauth authentication on download links. Do not create new session with SSPI authentication on download links. * Update documentation for the new 'SPNEGO with SSPI' login source * Mention in documentation that ROOT_URL should contain the FQDN of the server * Make sure that Contexter is not checking for active login sources when the ORM engine is not initialized (eg. when installing) * Always initialize and free SSO methods, even if they are not enabled, as a method can be activated while the app is running (from Authentication sources) * Add option in SSPIConfig for removing of domains from logon names * Update helper text for StripDomainNames option * Make sure handleSignIn() is called after a new user object is created by SSPI auth method * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Only make a query to the DB to check if SSPI is enabled on handlers that need that information for templates * Remove code duplication * Log errors in ActiveLoginSources Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert suffix of randomly generated E-mails for Reverse proxy authentication Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert unneeded white-space change in template Co-Authored-By: Lauris BH <lauris@nix.lv> * Add copyright comments at the top of new files * Use loopback name for randomly generated emails * Add locale tag for the SSPISeparatorReplacement field with proper casing * Revert casing of SSPISeparatorReplacement field in locale file, moving it up, next to other form fields * Update docs/content/doc/features/authentication.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Remove Priority() method and define the order in which SSO auth methods should be executed in one place * Log authenticated username only if it's not empty * Rephrase helper text for automatic creation of users * Return error if more than one active SSPI auth source is found * Change newUser() function to return error, letting caller log/handle the error * Move isPublicResource, isPublicPage and handleSignIn functions outside SSPI auth method to allow other SSO methods to reuse them if needed * Refactor initialization of the list containing SSO auth methods * Validate SSPI settings on POST * Change SSPI to only perform authentication on its own login page, API paths and download links. Leave Toggle middleware to redirect non authenticated users to login page * Make 'Default language' in SSPI config empty, unless changed by admin * Show error if admin tries to add a second authentication source of type SSPI * Simplify declaration of global variable * Rebuild gitgraph.js on Linux * Make sure config values containing only whitespace are not accepted
5 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
11 years ago
Add single sign-on support via SSPI on Windows (#8463) * Add single sign-on support via SSPI on Windows * Ensure plugins implement interface * Ensure plugins implement interface * Move functions used only by the SSPI auth method to sspi_windows.go * Field SSPISeparatorReplacement of AuthenticationForm should not be required via binding, as binding will insist the field is non-empty even if another login type is selected * Fix breaking of oauth authentication on download links. Do not create new session with SSPI authentication on download links. * Update documentation for the new 'SPNEGO with SSPI' login source * Mention in documentation that ROOT_URL should contain the FQDN of the server * Make sure that Contexter is not checking for active login sources when the ORM engine is not initialized (eg. when installing) * Always initialize and free SSO methods, even if they are not enabled, as a method can be activated while the app is running (from Authentication sources) * Add option in SSPIConfig for removing of domains from logon names * Update helper text for StripDomainNames option * Make sure handleSignIn() is called after a new user object is created by SSPI auth method * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Only make a query to the DB to check if SSPI is enabled on handlers that need that information for templates * Remove code duplication * Log errors in ActiveLoginSources Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert suffix of randomly generated E-mails for Reverse proxy authentication Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert unneeded white-space change in template Co-Authored-By: Lauris BH <lauris@nix.lv> * Add copyright comments at the top of new files * Use loopback name for randomly generated emails * Add locale tag for the SSPISeparatorReplacement field with proper casing * Revert casing of SSPISeparatorReplacement field in locale file, moving it up, next to other form fields * Update docs/content/doc/features/authentication.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Remove Priority() method and define the order in which SSO auth methods should be executed in one place * Log authenticated username only if it's not empty * Rephrase helper text for automatic creation of users * Return error if more than one active SSPI auth source is found * Change newUser() function to return error, letting caller log/handle the error * Move isPublicResource, isPublicPage and handleSignIn functions outside SSPI auth method to allow other SSO methods to reuse them if needed * Refactor initialization of the list containing SSO auth methods * Validate SSPI settings on POST * Change SSPI to only perform authentication on its own login page, API paths and download links. Leave Toggle middleware to redirect non authenticated users to login page * Make 'Default language' in SSPI config empty, unless changed by admin * Show error if admin tries to add a second authentication source of type SSPI * Simplify declaration of global variable * Rebuild gitgraph.js on Linux * Make sure config values containing only whitespace are not accepted
5 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
11 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
4 years ago
8 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
Add single sign-on support via SSPI on Windows (#8463) * Add single sign-on support via SSPI on Windows * Ensure plugins implement interface * Ensure plugins implement interface * Move functions used only by the SSPI auth method to sspi_windows.go * Field SSPISeparatorReplacement of AuthenticationForm should not be required via binding, as binding will insist the field is non-empty even if another login type is selected * Fix breaking of oauth authentication on download links. Do not create new session with SSPI authentication on download links. * Update documentation for the new 'SPNEGO with SSPI' login source * Mention in documentation that ROOT_URL should contain the FQDN of the server * Make sure that Contexter is not checking for active login sources when the ORM engine is not initialized (eg. when installing) * Always initialize and free SSO methods, even if they are not enabled, as a method can be activated while the app is running (from Authentication sources) * Add option in SSPIConfig for removing of domains from logon names * Update helper text for StripDomainNames option * Make sure handleSignIn() is called after a new user object is created by SSPI auth method * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Remove default value from text of form field helper Co-Authored-By: Lauris BH <lauris@nix.lv> * Only make a query to the DB to check if SSPI is enabled on handlers that need that information for templates * Remove code duplication * Log errors in ActiveLoginSources Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert suffix of randomly generated E-mails for Reverse proxy authentication Co-Authored-By: Lauris BH <lauris@nix.lv> * Revert unneeded white-space change in template Co-Authored-By: Lauris BH <lauris@nix.lv> * Add copyright comments at the top of new files * Use loopback name for randomly generated emails * Add locale tag for the SSPISeparatorReplacement field with proper casing * Revert casing of SSPISeparatorReplacement field in locale file, moving it up, next to other form fields * Update docs/content/doc/features/authentication.en-us.md Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Remove Priority() method and define the order in which SSO auth methods should be executed in one place * Log authenticated username only if it's not empty * Rephrase helper text for automatic creation of users * Return error if more than one active SSPI auth source is found * Change newUser() function to return error, letting caller log/handle the error * Move isPublicResource, isPublicPage and handleSignIn functions outside SSPI auth method to allow other SSO methods to reuse them if needed * Refactor initialization of the list containing SSO auth methods * Validate SSPI settings on POST * Change SSPI to only perform authentication on its own login page, API paths and download links. Leave Toggle middleware to redirect non authenticated users to login page * Make 'Default language' in SSPI config empty, unless changed by admin * Show error if admin tries to add a second authentication source of type SSPI * Simplify declaration of global variable * Rebuild gitgraph.js on Linux * Make sure config values containing only whitespace are not accepted
5 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
8 years ago
8 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package models
  6. import (
  7. "code.gitea.io/gitea/modules/auth/cloudbrain"
  8. "crypto/tls"
  9. "encoding/json"
  10. "errors"
  11. "fmt"
  12. "net/smtp"
  13. "net/textproto"
  14. "strings"
  15. "code.gitea.io/gitea/modules/auth/ldap"
  16. "code.gitea.io/gitea/modules/auth/oauth2"
  17. "code.gitea.io/gitea/modules/auth/pam"
  18. "code.gitea.io/gitea/modules/log"
  19. "code.gitea.io/gitea/modules/setting"
  20. "code.gitea.io/gitea/modules/timeutil"
  21. "github.com/unknwon/com"
  22. "xorm.io/xorm"
  23. "xorm.io/xorm/convert"
  24. )
  25. // LoginType represents an login type.
  26. type LoginType int
  27. // Note: new type must append to the end of list to maintain compatibility.
  28. const (
  29. LoginNoType LoginType = iota
  30. LoginPlain // 1
  31. LoginLDAP // 2
  32. LoginSMTP // 3
  33. LoginPAM // 4
  34. LoginDLDAP // 5
  35. LoginOAuth2 // 6
  36. LoginSSPI // 7
  37. LoginCloudBrain // 8
  38. )
  39. // LoginNames contains the name of LoginType values.
  40. var LoginNames = map[LoginType]string{
  41. LoginLDAP: "LDAP (via BindDN)",
  42. LoginDLDAP: "LDAP (simple auth)", // Via direct bind
  43. LoginSMTP: "SMTP",
  44. LoginPAM: "PAM",
  45. LoginOAuth2: "OAuth2",
  46. LoginSSPI: "SPNEGO with SSPI",
  47. LoginCloudBrain: "Cloud Brain",
  48. }
  49. // SecurityProtocolNames contains the name of SecurityProtocol values.
  50. var SecurityProtocolNames = map[ldap.SecurityProtocol]string{
  51. ldap.SecurityProtocolUnencrypted: "Unencrypted",
  52. ldap.SecurityProtocolLDAPS: "LDAPS",
  53. ldap.SecurityProtocolStartTLS: "StartTLS",
  54. }
  55. // Ensure structs implemented interface.
  56. var (
  57. _ convert.Conversion = &LDAPConfig{}
  58. _ convert.Conversion = &SMTPConfig{}
  59. _ convert.Conversion = &PAMConfig{}
  60. _ convert.Conversion = &OAuth2Config{}
  61. _ convert.Conversion = &SSPIConfig{}
  62. )
  63. // LDAPConfig holds configuration for LDAP login source.
  64. type LDAPConfig struct {
  65. *ldap.Source
  66. }
  67. // FromDB fills up a LDAPConfig from serialized format.
  68. func (cfg *LDAPConfig) FromDB(bs []byte) error {
  69. return json.Unmarshal(bs, &cfg)
  70. }
  71. // ToDB exports a LDAPConfig to a serialized format.
  72. func (cfg *LDAPConfig) ToDB() ([]byte, error) {
  73. return json.Marshal(cfg)
  74. }
  75. // SecurityProtocolName returns the name of configured security
  76. // protocol.
  77. func (cfg *LDAPConfig) SecurityProtocolName() string {
  78. return SecurityProtocolNames[cfg.SecurityProtocol]
  79. }
  80. // SMTPConfig holds configuration for the SMTP login source.
  81. type SMTPConfig struct {
  82. Auth string
  83. Host string
  84. Port int
  85. AllowedDomains string `xorm:"TEXT"`
  86. TLS bool
  87. SkipVerify bool
  88. }
  89. // FromDB fills up an SMTPConfig from serialized format.
  90. func (cfg *SMTPConfig) FromDB(bs []byte) error {
  91. return json.Unmarshal(bs, cfg)
  92. }
  93. // ToDB exports an SMTPConfig to a serialized format.
  94. func (cfg *SMTPConfig) ToDB() ([]byte, error) {
  95. return json.Marshal(cfg)
  96. }
  97. // PAMConfig holds configuration for the PAM login source.
  98. type PAMConfig struct {
  99. ServiceName string // pam service (e.g. system-auth)
  100. }
  101. // FromDB fills up a PAMConfig from serialized format.
  102. func (cfg *PAMConfig) FromDB(bs []byte) error {
  103. return json.Unmarshal(bs, &cfg)
  104. }
  105. // ToDB exports a PAMConfig to a serialized format.
  106. func (cfg *PAMConfig) ToDB() ([]byte, error) {
  107. return json.Marshal(cfg)
  108. }
  109. // OAuth2Config holds configuration for the OAuth2 login source.
  110. type OAuth2Config struct {
  111. Provider string
  112. ClientID string
  113. ClientSecret string
  114. OpenIDConnectAutoDiscoveryURL string
  115. CustomURLMapping *oauth2.CustomURLMapping
  116. }
  117. // FromDB fills up an OAuth2Config from serialized format.
  118. func (cfg *OAuth2Config) FromDB(bs []byte) error {
  119. return json.Unmarshal(bs, cfg)
  120. }
  121. // ToDB exports an SMTPConfig to a serialized format.
  122. func (cfg *OAuth2Config) ToDB() ([]byte, error) {
  123. return json.Marshal(cfg)
  124. }
  125. // SSPIConfig holds configuration for SSPI single sign-on.
  126. type SSPIConfig struct {
  127. AutoCreateUsers bool
  128. AutoActivateUsers bool
  129. StripDomainNames bool
  130. SeparatorReplacement string
  131. DefaultLanguage string
  132. }
  133. // FromDB fills up an SSPIConfig from serialized format.
  134. func (cfg *SSPIConfig) FromDB(bs []byte) error {
  135. return json.Unmarshal(bs, cfg)
  136. }
  137. // ToDB exports an SSPIConfig to a serialized format.
  138. func (cfg *SSPIConfig) ToDB() ([]byte, error) {
  139. return json.Marshal(cfg)
  140. }
  141. // LoginSource represents an external way for authorizing users.
  142. type LoginSource struct {
  143. ID int64 `xorm:"pk autoincr"`
  144. Type LoginType
  145. Name string `xorm:"UNIQUE"`
  146. IsActived bool `xorm:"INDEX NOT NULL DEFAULT false"`
  147. IsSyncEnabled bool `xorm:"INDEX NOT NULL DEFAULT false"`
  148. Cfg convert.Conversion `xorm:"TEXT"`
  149. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  150. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  151. }
  152. // Cell2Int64 converts a xorm.Cell type to int64,
  153. // and handles possible irregular cases.
  154. func Cell2Int64(val xorm.Cell) int64 {
  155. switch (*val).(type) {
  156. case []uint8:
  157. log.Trace("Cell2Int64 ([]uint8): %v", *val)
  158. return com.StrTo(string((*val).([]uint8))).MustInt64()
  159. }
  160. return (*val).(int64)
  161. }
  162. // BeforeSet is invoked from XORM before setting the value of a field of this object.
  163. func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
  164. if colName == "type" {
  165. switch LoginType(Cell2Int64(val)) {
  166. case LoginLDAP, LoginDLDAP:
  167. source.Cfg = new(LDAPConfig)
  168. case LoginSMTP:
  169. source.Cfg = new(SMTPConfig)
  170. case LoginPAM:
  171. source.Cfg = new(PAMConfig)
  172. case LoginOAuth2:
  173. source.Cfg = new(OAuth2Config)
  174. case LoginSSPI:
  175. source.Cfg = new(SSPIConfig)
  176. case LoginCloudBrain:
  177. source.Cfg = new(CloudBrainConfig)
  178. default:
  179. panic("unrecognized login source type: " + com.ToStr(*val))
  180. }
  181. }
  182. }
  183. // TypeName return name of this login source type.
  184. func (source *LoginSource) TypeName() string {
  185. return LoginNames[source.Type]
  186. }
  187. // IsLDAP returns true of this source is of the LDAP type.
  188. func (source *LoginSource) IsLDAP() bool {
  189. return source.Type == LoginLDAP
  190. }
  191. // IsDLDAP returns true of this source is of the DLDAP type.
  192. func (source *LoginSource) IsDLDAP() bool {
  193. return source.Type == LoginDLDAP
  194. }
  195. // IsSMTP returns true of this source is of the SMTP type.
  196. func (source *LoginSource) IsSMTP() bool {
  197. return source.Type == LoginSMTP
  198. }
  199. // IsPAM returns true of this source is of the PAM type.
  200. func (source *LoginSource) IsPAM() bool {
  201. return source.Type == LoginPAM
  202. }
  203. // IsOAuth2 returns true of this source is of the OAuth2 type.
  204. func (source *LoginSource) IsOAuth2() bool {
  205. return source.Type == LoginOAuth2
  206. }
  207. // IsSSPI returns true of this source is of the SSPI type.
  208. func (source *LoginSource) IsSSPI() bool {
  209. return source.Type == LoginSSPI
  210. }
  211. // HasTLS returns true of this source supports TLS.
  212. func (source *LoginSource) HasTLS() bool {
  213. return ((source.IsLDAP() || source.IsDLDAP()) &&
  214. source.LDAP().SecurityProtocol > ldap.SecurityProtocolUnencrypted) ||
  215. source.IsSMTP()
  216. }
  217. // UseTLS returns true of this source is configured to use TLS.
  218. func (source *LoginSource) UseTLS() bool {
  219. switch source.Type {
  220. case LoginLDAP, LoginDLDAP:
  221. return source.LDAP().SecurityProtocol != ldap.SecurityProtocolUnencrypted
  222. case LoginSMTP:
  223. return source.SMTP().TLS
  224. }
  225. return false
  226. }
  227. // SkipVerify returns true if this source is configured to skip SSL
  228. // verification.
  229. func (source *LoginSource) SkipVerify() bool {
  230. switch source.Type {
  231. case LoginLDAP, LoginDLDAP:
  232. return source.LDAP().SkipVerify
  233. case LoginSMTP:
  234. return source.SMTP().SkipVerify
  235. }
  236. return false
  237. }
  238. // LDAP returns LDAPConfig for this source, if of LDAP type.
  239. func (source *LoginSource) LDAP() *LDAPConfig {
  240. return source.Cfg.(*LDAPConfig)
  241. }
  242. // SMTP returns SMTPConfig for this source, if of SMTP type.
  243. func (source *LoginSource) SMTP() *SMTPConfig {
  244. return source.Cfg.(*SMTPConfig)
  245. }
  246. // PAM returns PAMConfig for this source, if of PAM type.
  247. func (source *LoginSource) PAM() *PAMConfig {
  248. return source.Cfg.(*PAMConfig)
  249. }
  250. // OAuth2 returns OAuth2Config for this source, if of OAuth2 type.
  251. func (source *LoginSource) OAuth2() *OAuth2Config {
  252. return source.Cfg.(*OAuth2Config)
  253. }
  254. // SSPI returns SSPIConfig for this source, if of SSPI type.
  255. func (source *LoginSource) SSPI() *SSPIConfig {
  256. return source.Cfg.(*SSPIConfig)
  257. }
  258. // CreateLoginSource inserts a LoginSource in the DB if not already
  259. // existing with the given name.
  260. func CreateLoginSource(source *LoginSource) error {
  261. has, err := x.Get(&LoginSource{Name: source.Name})
  262. if err != nil {
  263. return err
  264. } else if has {
  265. return ErrLoginSourceAlreadyExist{source.Name}
  266. }
  267. // Synchronization is only aviable with LDAP for now
  268. if !source.IsLDAP() {
  269. source.IsSyncEnabled = false
  270. }
  271. _, err = x.Insert(source)
  272. if err == nil && source.IsOAuth2() && source.IsActived {
  273. oAuth2Config := source.OAuth2()
  274. err = oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping)
  275. err = wrapOpenIDConnectInitializeError(err, source.Name, oAuth2Config)
  276. if err != nil {
  277. // remove the LoginSource in case of errors while registering OAuth2 providers
  278. if _, err := x.Delete(source); err != nil {
  279. log.Error("CreateLoginSource: Error while wrapOpenIDConnectInitializeError: %v", err)
  280. }
  281. return err
  282. }
  283. }
  284. return err
  285. }
  286. // LoginSources returns a slice of all login sources found in DB.
  287. func LoginSources() ([]*LoginSource, error) {
  288. auths := make([]*LoginSource, 0, 6)
  289. return auths, x.Find(&auths)
  290. }
  291. // LoginSourcesByType returns all sources of the specified type
  292. func LoginSourcesByType(loginType LoginType) ([]*LoginSource, error) {
  293. sources := make([]*LoginSource, 0, 1)
  294. if err := x.Where("type = ?", loginType).Find(&sources); err != nil {
  295. return nil, err
  296. }
  297. return sources, nil
  298. }
  299. // ActiveLoginSources returns all active sources of the specified type
  300. func ActiveLoginSources(loginType LoginType) ([]*LoginSource, error) {
  301. sources := make([]*LoginSource, 0, 1)
  302. if err := x.Where("is_actived = ? and type = ?", true, loginType).Find(&sources); err != nil {
  303. return nil, err
  304. }
  305. return sources, nil
  306. }
  307. // IsSSPIEnabled returns true if there is at least one activated login
  308. // source of type LoginSSPI
  309. func IsSSPIEnabled() bool {
  310. if !HasEngine {
  311. return false
  312. }
  313. sources, err := ActiveLoginSources(LoginSSPI)
  314. if err != nil {
  315. log.Error("ActiveLoginSources: %v", err)
  316. return false
  317. }
  318. return len(sources) > 0
  319. }
  320. // GetLoginSourceByID returns login source by given ID.
  321. func GetLoginSourceByID(id int64) (*LoginSource, error) {
  322. source := new(LoginSource)
  323. has, err := x.ID(id).Get(source)
  324. if err != nil {
  325. return nil, err
  326. } else if !has {
  327. return nil, ErrLoginSourceNotExist{id}
  328. }
  329. return source, nil
  330. }
  331. // UpdateSource updates a LoginSource record in DB.
  332. func UpdateSource(source *LoginSource) error {
  333. var originalLoginSource *LoginSource
  334. if source.IsOAuth2() {
  335. // keep track of the original values so we can restore in case of errors while registering OAuth2 providers
  336. var err error
  337. if originalLoginSource, err = GetLoginSourceByID(source.ID); err != nil {
  338. return err
  339. }
  340. }
  341. _, err := x.ID(source.ID).AllCols().Update(source)
  342. if err == nil && source.IsOAuth2() && source.IsActived {
  343. oAuth2Config := source.OAuth2()
  344. err = oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping)
  345. err = wrapOpenIDConnectInitializeError(err, source.Name, oAuth2Config)
  346. if err != nil {
  347. // restore original values since we cannot update the provider it self
  348. if _, err := x.ID(source.ID).AllCols().Update(originalLoginSource); err != nil {
  349. log.Error("UpdateSource: Error while wrapOpenIDConnectInitializeError: %v", err)
  350. }
  351. return err
  352. }
  353. }
  354. return err
  355. }
  356. // DeleteSource deletes a LoginSource record in DB.
  357. func DeleteSource(source *LoginSource) error {
  358. count, err := x.Count(&User{LoginSource: source.ID})
  359. if err != nil {
  360. return err
  361. } else if count > 0 {
  362. return ErrLoginSourceInUse{source.ID}
  363. }
  364. count, err = x.Count(&ExternalLoginUser{LoginSourceID: source.ID})
  365. if err != nil {
  366. return err
  367. } else if count > 0 {
  368. return ErrLoginSourceInUse{source.ID}
  369. }
  370. if source.IsOAuth2() {
  371. oauth2.RemoveProvider(source.Name)
  372. }
  373. _, err = x.ID(source.ID).Delete(new(LoginSource))
  374. return err
  375. }
  376. // CountLoginSources returns number of login sources.
  377. func CountLoginSources() int64 {
  378. count, _ := x.Count(new(LoginSource))
  379. return count
  380. }
  381. // .____ ________ _____ __________
  382. // | | \______ \ / _ \\______ \
  383. // | | | | \ / /_\ \| ___/
  384. // | |___ | ` \/ | \ |
  385. // |_______ \/_______ /\____|__ /____|
  386. // \/ \/ \/
  387. func composeFullName(firstname, surname, username string) string {
  388. switch {
  389. case len(firstname) == 0 && len(surname) == 0:
  390. return username
  391. case len(firstname) == 0:
  392. return surname
  393. case len(surname) == 0:
  394. return firstname
  395. default:
  396. return firstname + " " + surname
  397. }
  398. }
  399. // LoginViaLDAP queries if login/password is valid against the LDAP directory pool,
  400. // and create a local user if success when enabled.
  401. func LoginViaLDAP(user *User, login, password string, source *LoginSource) (*User, error) {
  402. sr := source.Cfg.(*LDAPConfig).SearchEntry(login, password, source.Type == LoginDLDAP)
  403. if sr == nil {
  404. // User not in LDAP, do nothing
  405. return nil, ErrUserNotExist{0, login, 0}
  406. }
  407. var isAttributeSSHPublicKeySet = len(strings.TrimSpace(source.LDAP().AttributeSSHPublicKey)) > 0
  408. // Update User admin flag if exist
  409. if isExist, err := IsUserExist(0, sr.Username); err != nil {
  410. return nil, err
  411. } else if isExist {
  412. if user == nil {
  413. user, err = GetUserByName(sr.Username)
  414. if err != nil {
  415. return nil, err
  416. }
  417. }
  418. if user != nil && !user.ProhibitLogin {
  419. cols := make([]string, 0)
  420. if len(source.LDAP().AdminFilter) > 0 && user.IsAdmin != sr.IsAdmin {
  421. // Change existing admin flag only if AdminFilter option is set
  422. user.IsAdmin = sr.IsAdmin
  423. cols = append(cols, "is_admin")
  424. }
  425. if !user.IsAdmin && len(source.LDAP().RestrictedFilter) > 0 && user.IsRestricted != sr.IsRestricted {
  426. // Change existing restricted flag only if RestrictedFilter option is set
  427. user.IsRestricted = sr.IsRestricted
  428. cols = append(cols, "is_restricted")
  429. }
  430. if len(cols) > 0 {
  431. err = UpdateUserCols(user, cols...)
  432. if err != nil {
  433. return nil, err
  434. }
  435. }
  436. }
  437. }
  438. if user != nil {
  439. if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
  440. return user, RewriteAllPublicKeys()
  441. }
  442. return user, nil
  443. }
  444. // Fallback.
  445. if len(sr.Username) == 0 {
  446. sr.Username = login
  447. }
  448. if len(sr.Mail) == 0 {
  449. sr.Mail = fmt.Sprintf("%s@localhost", sr.Username)
  450. }
  451. user = &User{
  452. LowerName: strings.ToLower(sr.Username),
  453. Name: sr.Username,
  454. FullName: composeFullName(sr.Name, sr.Surname, sr.Username),
  455. Email: sr.Mail,
  456. LoginType: source.Type,
  457. LoginSource: source.ID,
  458. LoginName: login,
  459. IsActive: true,
  460. IsAdmin: sr.IsAdmin,
  461. IsRestricted: sr.IsRestricted,
  462. }
  463. err := CreateUser(user)
  464. if err == nil && isAttributeSSHPublicKeySet && addLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
  465. err = RewriteAllPublicKeys()
  466. }
  467. return user, err
  468. }
  469. // _________ __________________________
  470. // / _____/ / \__ ___/\______ \
  471. // \_____ \ / \ / \| | | ___/
  472. // / \/ Y \ | | |
  473. // /_______ /\____|__ /____| |____|
  474. // \/ \/
  475. type smtpLoginAuth struct {
  476. username, password string
  477. }
  478. func (auth *smtpLoginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
  479. return "LOGIN", []byte(auth.username), nil
  480. }
  481. func (auth *smtpLoginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
  482. if more {
  483. switch string(fromServer) {
  484. case "Username:":
  485. return []byte(auth.username), nil
  486. case "Password:":
  487. return []byte(auth.password), nil
  488. }
  489. }
  490. return nil, nil
  491. }
  492. // SMTP authentication type names.
  493. const (
  494. SMTPPlain = "PLAIN"
  495. SMTPLogin = "LOGIN"
  496. )
  497. // SMTPAuths contains available SMTP authentication type names.
  498. var SMTPAuths = []string{SMTPPlain, SMTPLogin}
  499. // SMTPAuth performs an SMTP authentication.
  500. func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
  501. c, err := smtp.Dial(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port))
  502. if err != nil {
  503. return err
  504. }
  505. defer c.Close()
  506. if err = c.Hello("gogs"); err != nil {
  507. return err
  508. }
  509. if cfg.TLS {
  510. if ok, _ := c.Extension("STARTTLS"); ok {
  511. if err = c.StartTLS(&tls.Config{
  512. InsecureSkipVerify: cfg.SkipVerify,
  513. ServerName: cfg.Host,
  514. }); err != nil {
  515. return err
  516. }
  517. } else {
  518. return errors.New("SMTP server unsupports TLS")
  519. }
  520. }
  521. if ok, _ := c.Extension("AUTH"); ok {
  522. return c.Auth(a)
  523. }
  524. return ErrUnsupportedLoginType
  525. }
  526. // LoginViaSMTP queries if login/password is valid against the SMTP,
  527. // and create a local user if success when enabled.
  528. func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPConfig) (*User, error) {
  529. // Verify allowed domains.
  530. if len(cfg.AllowedDomains) > 0 {
  531. idx := strings.Index(login, "@")
  532. if idx == -1 {
  533. return nil, ErrUserNotExist{0, login, 0}
  534. } else if !com.IsSliceContainsStr(strings.Split(cfg.AllowedDomains, ","), login[idx+1:]) {
  535. return nil, ErrUserNotExist{0, login, 0}
  536. }
  537. }
  538. var auth smtp.Auth
  539. if cfg.Auth == SMTPPlain {
  540. auth = smtp.PlainAuth("", login, password, cfg.Host)
  541. } else if cfg.Auth == SMTPLogin {
  542. auth = &smtpLoginAuth{login, password}
  543. } else {
  544. return nil, errors.New("Unsupported SMTP auth type")
  545. }
  546. if err := SMTPAuth(auth, cfg); err != nil {
  547. // Check standard error format first,
  548. // then fallback to worse case.
  549. tperr, ok := err.(*textproto.Error)
  550. if (ok && tperr.Code == 535) ||
  551. strings.Contains(err.Error(), "Username and Password not accepted") {
  552. return nil, ErrUserNotExist{0, login, 0}
  553. }
  554. return nil, err
  555. }
  556. if user != nil {
  557. return user, nil
  558. }
  559. username := login
  560. idx := strings.Index(login, "@")
  561. if idx > -1 {
  562. username = login[:idx]
  563. }
  564. user = &User{
  565. LowerName: strings.ToLower(username),
  566. Name: strings.ToLower(username),
  567. Email: login,
  568. Passwd: password,
  569. LoginType: LoginSMTP,
  570. LoginSource: sourceID,
  571. LoginName: login,
  572. IsActive: true,
  573. }
  574. return user, CreateUser(user)
  575. }
  576. // __________ _____ _____
  577. // \______ \/ _ \ / \
  578. // | ___/ /_\ \ / \ / \
  579. // | | / | \/ Y \
  580. // |____| \____|__ /\____|__ /
  581. // \/ \/
  582. // LoginViaPAM queries if login/password is valid against the PAM,
  583. // and create a local user if success when enabled.
  584. func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMConfig) (*User, error) {
  585. pamLogin, err := pam.Auth(cfg.ServiceName, login, password)
  586. if err != nil {
  587. if strings.Contains(err.Error(), "Authentication failure") {
  588. return nil, ErrUserNotExist{0, login, 0}
  589. }
  590. return nil, err
  591. }
  592. if user != nil {
  593. return user, nil
  594. }
  595. // Allow PAM sources with `@` in their name, like from Active Directory
  596. username := pamLogin
  597. idx := strings.Index(pamLogin, "@")
  598. if idx > -1 {
  599. username = pamLogin[:idx]
  600. }
  601. user = &User{
  602. LowerName: strings.ToLower(username),
  603. Name: username,
  604. Email: pamLogin,
  605. Passwd: password,
  606. LoginType: LoginPAM,
  607. LoginSource: sourceID,
  608. LoginName: login, // This is what the user typed in
  609. IsActive: true,
  610. }
  611. return user, CreateUser(user)
  612. }
  613. // ExternalUserLogin attempts a login using external source types.
  614. func ExternalUserLogin(user *User, login, password string, source *LoginSource) (*User, error) {
  615. if !source.IsActived {
  616. return nil, ErrLoginSourceNotActived
  617. }
  618. var err error
  619. switch source.Type {
  620. case LoginLDAP, LoginDLDAP:
  621. user, err = LoginViaLDAP(user, login, password, source)
  622. case LoginSMTP:
  623. user, err = LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig))
  624. case LoginPAM:
  625. user, err = LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig))
  626. case LoginCloudBrain:
  627. user, err = LoginViaCloudBrain(user, login, password, source)
  628. default:
  629. return nil, ErrUnsupportedLoginType
  630. }
  631. if err != nil {
  632. return nil, err
  633. }
  634. // WARN: DON'T check user.IsActive, that will be checked on reqSign so that
  635. // user could be hint to resend confirm email.
  636. if user.ProhibitLogin {
  637. return nil, ErrUserProhibitLogin{user.ID, user.Name}
  638. }
  639. return user, nil
  640. }
  641. // UserSignIn validates user name and password.
  642. func UserSignIn(username, password string) (*User, error) {
  643. var user *User
  644. if strings.Contains(username, "@") {
  645. user = &User{Email: strings.ToLower(strings.TrimSpace(username))}
  646. // check same email
  647. cnt, err := x.Count(user)
  648. if err != nil {
  649. return nil, err
  650. }
  651. if cnt > 1 {
  652. return nil, ErrEmailAlreadyUsed{
  653. Email: user.Email,
  654. }
  655. }
  656. } else {
  657. trimmedUsername := strings.TrimSpace(username)
  658. if len(trimmedUsername) == 0 {
  659. return nil, ErrUserNotExist{0, username, 0}
  660. }
  661. user = &User{LowerName: strings.ToLower(trimmedUsername)}
  662. }
  663. hasUser, err := x.Get(user)
  664. if err != nil {
  665. return nil, err
  666. }
  667. if hasUser {
  668. switch user.LoginType {
  669. case LoginNoType, LoginPlain, LoginOAuth2:
  670. if user.IsPasswordSet() && user.ValidatePassword(password) {
  671. // Update password hash if server password hash algorithm have changed
  672. if user.PasswdHashAlgo != setting.PasswordHashAlgo {
  673. user.HashPassword(password)
  674. if err := UpdateUserCols(user, "passwd", "passwd_hash_algo"); err != nil {
  675. return nil, err
  676. }
  677. }
  678. // WARN: DON'T check user.IsActive, that will be checked on reqSign so that
  679. // user could be hint to resend confirm email.
  680. if user.ProhibitLogin {
  681. return nil, ErrUserProhibitLogin{user.ID, user.Name}
  682. }
  683. return user, nil
  684. }
  685. return nil, ErrUserNotExist{user.ID, user.Name, 0}
  686. default:
  687. var source LoginSource
  688. hasSource, err := x.ID(user.LoginSource).Get(&source)
  689. if err != nil {
  690. return nil, err
  691. } else if !hasSource {
  692. return nil, ErrLoginSourceNotExist{user.LoginSource}
  693. }
  694. return ExternalUserLogin(user, user.LoginName, password, &source)
  695. }
  696. }
  697. sources := make([]*LoginSource, 0, 5)
  698. if err = x.Where("is_actived = ?", true).Find(&sources); err != nil {
  699. return nil, err
  700. }
  701. for _, source := range sources {
  702. if source.IsOAuth2() || source.IsSSPI() {
  703. // don't try to authenticate against OAuth2 and SSPI sources here
  704. continue
  705. }
  706. authUser, err := ExternalUserLogin(nil, username, password, source)
  707. if err == nil {
  708. return authUser, nil
  709. }
  710. log.Warn("Failed to login '%s' via '%s': %v", username, source.Name, err)
  711. }
  712. return nil, ErrUserNotExist{user.ID, user.Name, 0}
  713. }
  714. func LoginViaCloudBrain(user *User, login, password string, source *LoginSource) (*User, error) {
  715. token, err := cloudbrain.UserValidate(login, password)
  716. if err != nil {
  717. log.Error("UserValidate(%s) failed: %v", login, err)
  718. return nil, err
  719. }
  720. if user != nil {
  721. user.Token = token
  722. return user, UpdateUserCols(user, "token")
  723. }
  724. cloudBrainUser, err := cloudbrain.GetUserInfo(login, token)
  725. if err != nil {
  726. log.Error("GetUserInfo(%s) failed: %v", login, err)
  727. return nil, err
  728. }
  729. if len(cloudBrainUser.Email) == 0 {
  730. cloudBrainUser.Email = fmt.Sprintf("%s@cloudbrain", login)
  731. }
  732. user = &User{
  733. LowerName: strings.ToLower(login),
  734. Name: login,
  735. Email: cloudBrainUser.Email,
  736. LoginType: source.Type,
  737. LoginSource: source.ID,
  738. LoginName: login,
  739. IsActive: true,
  740. Token: token,
  741. }
  742. err = CreateUser(user)
  743. if err != nil {
  744. log.Error("CreateUser(%s) failed: %v", login, err)
  745. return nil, err
  746. }
  747. return user, nil
  748. }