Skip to content

Conversation

@Rainer-Keller
Copy link
Contributor

This pull request is based on #1219, but has everything unrelated to SAML removed and all the review issues fixed.

@dsl400
Copy link

dsl400 commented Sep 15, 2024

WARN: Bad key in configuration file: "route".
this will remove the option to configure routes locally and bypass the configuration coming from the server?

@Rainer-Keller
Copy link
Contributor Author

WARN: Bad key in configuration file: "route". this will remove the option to configure routes locally and bypass the configuration coming from the server?

I've extracted only the SAML feature from your branch for easier review. The configuration options for dns and route overwrite I did not adopt. These options may go in as a separate pull request.

@dsl400
Copy link

dsl400 commented Sep 15, 2024

I will wait for this to be merged first

@Rainer-Keller
Copy link
Contributor Author

I will wait for this to be merged first

Let's see how it goes...

@Rainer-Keller Rainer-Keller force-pushed the master branch 2 times, most recently from 412e692 to 191099c Compare September 21, 2024 05:06
@exzombie
Copy link

exzombie commented Oct 2, 2024

How does this compare to #1217?

@Rainer-Keller
Copy link
Contributor Author

How does this compare to #1217?

At a first glance it looks like both MRs are doing about the same.

@dsl400
Copy link

dsl400 commented Oct 2, 2024

Not sure if something changed since I posted this comment

@exzombie
Copy link

exzombie commented Oct 2, 2024

Not sure if something changed since I posted this comment

It hasn't AFAICT, but all I get from your comment is that it's an independently developed alternative, and that you have implemented some additional features. Now, @Rainer-Keller has put some effort into breaking this up into manageable pieces, so I thought that there was some reason why this alternative implementation was deemed better.

Hopefully, in the near future, I'll have some time to try out one or the other implementation. I'm not convinced having two to test is better than one 😅

@Rainer-Keller
Copy link
Contributor Author

@exzombie Yours looks fine as well. It has the extra option to pass the auth ID from the command line. But not sure of what use that is.
I was not aware that there is a 3rd implementation. The first one I found was the one from @dsl400 .
I left some comments on your MR ;)

If would be good to get some feedback from a maintainer which of these changes has the highest chance to get in. Otherwise we'll have double effort.
Once we know which one it is, I'll make some suggestions for error/debug message rephrasing.

@exzombie
Copy link

exzombie commented Oct 2, 2024

@exzombie Yours looks fine as well. It has the extra option to pass the auth ID from the command line. But not sure of what use that is.
I was not aware that there is a 3rd implementation. The first one I found was the one from @dsl400 .
I left some comments on your MR ;)

There seems to be some confusion, that MR is not mine, it is from @filippor. And are you sure there's a third one?

Anyway, thanks for reviewing that MR; I haven't taken the time yet, I'm still waiting for some prerequisites to fall into place. I hope we'll be able to move the SAML story forward, and that FortiClient updates won't break EMS, but that's a different ball of hair ...

@mrbaseman
Copy link
Collaborator

Actually, this pull request looks quite clean to me. I have been hesitant to dependencies on too many external tools, and also workflows involving sudo and pipes. Although I haven't recapitulated all discussions in the previous pull requests, and honestly I didn't do a detailed code review of them, I would still vote for this one. The reason for me is, that @Rainer-Keller has dropped several unrelated changes, and thereby has made the change much more readable and understandable. There are also a couple of potentially security related fixes included in this PR, compared to the original one.
Since I didn't have the time to take care of this project recently, I would like to hear the opinion of the other maintainers, too (I did follow the github discussions, but currently I'm not that much involved in the code development anymore)

@Rainer-Keller
Copy link
Contributor Author

Rainer-Keller commented Oct 3, 2024

@exzombie
Right, seems I treated the PR you sent as if was yours.

I'm still waiting for some prerequisites to fall into place

Any details on what prerequisites that are?
Microsoft has dropped support for external 2nd factor (not sure if that is the right term). So right now, SAML is the only option. I'm using my custom built version at the moment.

And are you sure there's a third one?

There are solutions out there that seems to use a special built browser tool to extract the SAML id and forward this to openfortivpn.

@mrbaseman

I have been hesitant to dependencies on too many external tools, and also workflows involving sudo and pipes

Pipes have been used in the original MR from @dsl400 , but these were unrelated to SAML and I have removed them.

This would be my summary of the two PRs

#1241

  • Better error messages
  • Issues already resolved
  • More checks on the SAML id
  • Intuitive names of variables, functions and commandline options
  • User documentation

#1217

  • (a little) Less lines code
  • Realm support
  • HTML output for the response
  • Option to pass the SAML id on the commandline

If we all agree it is my PR that it the preferred candidate, then I can integrate the features from #1217 here as well.

@exzombie
Copy link

exzombie commented Oct 3, 2024

@Rainer-Keller

Any details on what prerequisites that are?

Our internal stuff, mostly, and Fortinet dragging their feet with supporting Ubuntu 24.04. So, nothing you need to bother yourself with.

There are solutions out there that seems to use a special built browser tool to extract the SAML id and forward this to openfortivpn.

Ah, ok. Just making sure I haven't missed another attempt at what I consider a proper SAML implementation.

@filippor
Copy link

filippor commented Oct 4, 2024

Hello I create the pull request #1217 when I found the way to implement it using external browser. I'm not a c developer. Thanks for the code review. If it is needed I will fix the issue. I have no problems if this one will be merged. But I will wait for a word from a maintainer to complete my PR. It is working as is for my needs

Copy link

@exzombie exzombie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! Thanks again for taking the time to push this feature forward. I'm happy with the simplicity of the approach, the "HTTP server" is really lightweight. That said, dealing with strings in C is one of the things I personally hate quite a bit, and the approach taken in the HTTP server does not convince me that the code is safe. I made some suggestions, hope you find them helpful.

return -1;
}

strncpy(id, &request[id_start], id_length);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused here. id_length is determined by looking for a space. Then, you use this length with strncpy, which will not insert a null terminator at id[id_length-1]. And yet, the data in id is expected to be null terminated, because it's used with strlen in http.c. If this code works, I guess it's because id happens to be initialized to zeros. But we can't rely on that.

I suggest using memcpy and adding a null at the end explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section was taken from the original author. I've replaced it with a completely different approach.

@Rainer-Keller Rainer-Keller force-pushed the master branch 3 times, most recently from 8791318 to a91b087 Compare October 10, 2024 12:47
@Rainer-Keller Rainer-Keller force-pushed the master branch 3 times, most recently from 67769e6 to 400c787 Compare October 11, 2024 04:59
@DimitriPapadopoulos
Copy link
Collaborator

The remaining linter warnings are indentation warnings.

You can run the linters locally using ./tests/lint/run.sh.

@Rainer-Keller
Copy link
Contributor Author

Ah, ok. I now see the problem. My assumption was that the project uses tab indentation. But looks like like the linters use mixed indentation. Half tabs half spaces.

@Rainer-Keller
Copy link
Contributor Author

Ok, now applied the patch directly with mixed indenting.

@Rainer-Keller
Copy link
Contributor Author

Rainer-Keller commented Feb 2, 2025

Hmm. My local lint run did produce a patch that is not accepted by the one in github.

@DimitriPapadopoulos
Copy link
Collaborator

You must be lacking astyle locally. We should fix the script should to emit an error message.

@Rainer-Keller
Copy link
Contributor Author

Rainer-Keller commented Feb 2, 2025

You must be lacking astyle locally. We should fix the script should to emit an error message.

There is a warning about it. I've installed it to get the patch. Version 3.6.6 comes with my distro.

However, the last remaining style issue I also get locally. The messages are quite long, should I really make them a single long line? There were other style issues where long lines were not wanted.

@DimitriPapadopoulos
Copy link
Collaborator

I agree multiple lines are better in this case. I'm not sure how to silence checkpatch.pl in this case.

@Rainer-Keller
Copy link
Contributor Author

The script seems to not complain when assigning a static const char *.
I'll try to move the message.

@Rainer-Keller
Copy link
Contributor Author

Rainer-Keller commented Feb 2, 2025

Moving did not solve it. But turns out adding line breaks to the string makes code checker happy.

src/http.c Outdated
if (username[0] == '\0' && tunnel->config->password[0] == '\0') {
if (strlen(tunnel->config->saml_session_id) > 0) {
// SAML login
static const char *uri_pattern = "/remote/saml/auth_id?id=%s";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static const char *uri_pattern = "/remote/saml/auth_id?id=%s";
static const char uri_pattern[] = "/remote/saml/auth_id?id=%s";

// Desired string is
// https://company.com:port/remote/saml/start?redirect=1(&realm=<str>)
// with the realm being optional
static const char *uri_pattern = "https://%s:%d/remote/saml/start?redirect=1%s%s";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static const char *uri_pattern = "https://%s:%d/remote/saml/start?redirect=1%s%s";
static const char uri_pattern[] = "https://%s:%d/remote/saml/start?redirect=1%s%s";

// after being redirected from the Fortinet Server.
static void send_status_response(int socket, const char *userMessage)
{
static const char *replyHeader = "HTTP/1.1 200 OK\r\n"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static const char *replyHeader = "HTTP/1.1 200 OK\r\n"
static const char replyHeader[] = "HTTP/1.1 200 OK\r\n"

"Connection: close\r\n"
"\r\n";

static const char *replyBody = "<!DOCTYPE html>\r\n"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static const char *replyBody = "<!DOCTYPE html>\r\n"
static const char replyBody[] = "<!DOCTYPE html>\r\n"

@@ -0,0 +1,295 @@
#include <netinet/in.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a copyright statement at the top.

Copy link
Collaborator

@DimitriPapadopoulos DimitriPapadopoulos Feb 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I would reorganise includes as follows, for consistency with the other files:

#include "config.h"
#include "http.h"
#include "log.h"
#include "tunnel.h"

#include <unistd.h>
#include <netinet/tcp.h>
#include <sys/select.h>

#include <ctype.h>
#include <string.h>

That is:

  1. openfortivpn header files
  2. POSIX header files
  3. ISO C header files

* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last thing, don't forget to include the relevant header first:

Suggested change
#include "http_server.h"

*/

#include "config.h"
#include "http.h" // for url_encode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either we document why we include headers for all of them, or for none of them. We have chosen the latter so far:

Suggested change
#include "http.h" // for url_encode
#include "http.h"

@DimitriPapadopoulos
Copy link
Collaborator

@mrbaseman Linter issues and other details have been fixed. Would you mind having a last look at the source code?

request[sizeof(request) - 1] = 0;
request[read_result] = 0;

static const char *request_head = "GET /?id=";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I missed this one:

Suggested change
static const char *request_head = "GET /?id=";
static const char request_head[] = "GET /?id=";

}

// Extract the id
static const char *token_delimiter = " &\r\n";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this one:

Suggested change
static const char *token_delimiter = " &\r\n";
static const char token_delimiter[] = " &\r\n";

src/tunnel.c Outdated
const char *eol = NULL;

for (int i = 0; (i < ARRAY_SIZE(HTTP_EOL)) &&
for (unsigned int i = 0; (i < ARRAY_SIZE(HTTP_EOL)) &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

If the rationale was type correctness, size_t might be a better candidate as the type of ARRAY_SIZE() is size_t.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I'll switch to size_t then.

This change is based on work from Valentin Sasek <[email protected]>
Fix compiler warnings about comparing signed with unsigned integers.
@mrbaseman
Copy link
Collaborator

@mrbaseman Linter issues and other details have been fixed. Would you mind having a last look at the source code?

It's fine for me. I have just run the checks once more on the latest force-pushed commits and reviewed the last changes. I'll merge it now.

@mrbaseman mrbaseman merged commit fa560c9 into adrienverge:master Feb 2, 2025
5 checks passed
@mrbaseman
Copy link
Collaborator

done. Thanks to all who have contributed, especially to @Rainer-Keller who has put a lot of effort in improving the saml code.

@mvillafuertem
Copy link

Thanks to all, @mrbaseman when will we have a release tagged with this feature?

@mrbaseman
Copy link
Collaborator

Openfortivpn 1.23.0 has just been tagged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants