Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gitlab bearer authentication #604

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions legend-sdlc-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@
<groupId>org.pac4j</groupId>
<artifactId>pac4j-oidc</artifactId>
</dependency>
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-http</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2020 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.sdlc.server.gitlab.auth;

import org.finos.legend.sdlc.server.auth.BaseCommonProfileSession;
import org.finos.legend.sdlc.server.auth.Token;
import org.finos.legend.server.pac4j.gitlab.GitlabDirectAccessTokenProfile;
import org.finos.legend.server.pac4j.gitlab.GitlabPersonalAccessTokenProfile;
import org.gitlab4j.api.Constants.TokenType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.util.Objects;

public class GitLabDirectAccessTokenSession extends BaseCommonProfileSession<GitlabDirectAccessTokenProfile> implements GitLabSession
{
private static final Logger LOGGER = LoggerFactory.getLogger(GitLabDirectAccessTokenSession.class);

private final GitLabTokenManager tokenManager;

protected GitLabDirectAccessTokenSession(GitlabDirectAccessTokenProfile profile, String userId, Instant creationTime, GitLabTokenManager tokenManager)
{
super(profile, userId, creationTime);
this.tokenManager = possiblyInitializeTokenManager(tokenManager, profile);
}

@Override
public boolean equals(Object other)
{
if (this == other)
{
return true;
}

if (!(other instanceof GitLabDirectAccessTokenSession))
{
return false;
}

GitLabDirectAccessTokenSession that = (GitLabDirectAccessTokenSession) other;
return Objects.equals(this.getUserId(), that.getUserId()) &&
Objects.equals(this.getProfile(), that.getProfile()) &&
this.getCreationTime().equals(that.getCreationTime()) &&
this.tokenManager.equals(that.tokenManager);
}

@Override
public int hashCode()
{
return getCreationTime().hashCode() ^ getUserId().hashCode() ^ this.tokenManager.hashCode();
}

@Override
public boolean gitLabOAuthCallback(String code)
{
return this.tokenManager.gitLabOAuthCallback(code);
}

@Override
public GitLabToken getGitLabToken()
{
return this.tokenManager.getGitLabToken();
}

@Override
public void clearGitLabToken()
{
this.tokenManager.clearGitLabToken();
}

@Override
public void setGitLabToken(GitLabToken token)
{
this.tokenManager.setGitLabToken(token);
}

@Override
public Token.TokenBuilder encode(Token.TokenBuilder builder)
{
return this.tokenManager.encode(super.encode(builder));
}

@Override
protected void writeToStringInfo(StringBuilder builder)
{
this.tokenManager.appendGitLabTokenInfo(builder.append(' '));
}

private static GitLabTokenManager possiblyInitializeTokenManager(GitLabTokenManager tokenManager, GitlabDirectAccessTokenProfile profile)
{
if ((tokenManager != null) && (profile != null))
{
LOGGER.debug("initializing with GitLab Direct Access Token profile: {}", profile);
String token = profile.getPersonalAccessToken();

if (token != null &&
profile.getGitlabHost() != null &&
tokenManager.getAppInfo().getServerInfo().getHost().equals(profile.getGitlabHost()))
{
tokenManager.setGitLabToken(GitLabToken.newGitLabToken(TokenType.OAUTH2_ACCESS, token));
LOGGER.debug("Storing private access token from GitLab Direct Access Token profile");
}
}
return tokenManager;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.finos.legend.sdlc.server.auth.SessionBuilder;
import org.finos.legend.sdlc.server.auth.Token;
import org.finos.legend.sdlc.server.gitlab.GitLabAppInfo;
import org.finos.legend.server.pac4j.gitlab.GitlabDirectAccessTokenProfile;
import org.finos.legend.server.pac4j.gitlab.GitlabPersonalAccessTokenProfile;
import org.finos.legend.server.pac4j.kerberos.KerberosProfile;
import org.pac4j.core.profile.CommonProfile;
Expand Down Expand Up @@ -122,12 +123,16 @@ protected GitLabSession newSession()
{
return new GitLabPersonalAccessTokenSession((GitlabPersonalAccessTokenProfile) this.profile, getUserId(), getCreationTime(), this.tokenManager);
}
if (this.profile instanceof GitlabDirectAccessTokenProfile)
{
return new GitLabDirectAccessTokenSession((GitlabDirectAccessTokenProfile) this.profile, getUserId(), getCreationTime(), this.tokenManager);
}
throw new IllegalStateException("Unsupported profile type: " + profile);
}

static boolean isSupportedProfile(CommonProfile profile)
{
return (profile instanceof KerberosProfile) || (profile instanceof OidcProfile) || (profile instanceof GitlabPersonalAccessTokenProfile);
return (profile instanceof KerberosProfile) || (profile instanceof OidcProfile) || (profile instanceof GitlabPersonalAccessTokenProfile) || (profile instanceof GitlabDirectAccessTokenProfile);
}

static GitLabSessionBuilder newBuilder(GitLabAppInfo appInfo)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2021 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.server.pac4j.gitlab;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.credentials.authenticator.Authenticator;
import org.pac4j.core.exception.CredentialsException;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class GitlabDirectAccessTokenAuthenticator implements Authenticator<TokenCredentials>
{
private final String apiVersion;
private final String host;
private final String scheme;
private final ObjectReader reader;

public GitlabDirectAccessTokenAuthenticator(String scheme, String gitlabHost, String gitlabApiVersion)
{
this.scheme = scheme;
this.host = gitlabHost;
this.apiVersion = gitlabApiVersion;
this.reader = JsonMapper.builder().build().readerFor(UserInformation.class);
}

@Override
public void validate(TokenCredentials credentials, WebContext webContext)
{
// TODO - epsstan - Validate the token by using the token endpoint .. like the OidcAuthenticator
}

@JsonIgnoreProperties(ignoreUnknown = true)
private static class UserInformation
{
@JsonProperty("username")
private String username;

@JsonProperty("name")
private String name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2021 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.server.pac4j.gitlab;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.finos.legend.server.pac4j.SerializableProfile;
import org.pac4j.http.client.direct.DirectBearerAuthClient;


@SerializableProfile
public class GitlabDirectAccessTokenClient extends DirectBearerAuthClient
{
@JsonProperty
public String headerTokenName;

@JsonProperty
public String scheme;

@JsonProperty
public String gitlabApiVersion;

@JsonProperty
public String gitlabHost;

@Override
public String getName()
{
return "TODO";
}

@Override
protected void clientInit()
{
defaultAuthenticator(new GitlabDirectAccessTokenAuthenticator(scheme, gitlabHost, gitlabApiVersion));
defaultCredentialsExtractor(new GitlabDirectAccessTokenExtractor(headerTokenName));
defaultProfileCreator(new GitlabDirectAccessTokenProfileCreator(gitlabHost));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2021 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.server.pac4j.gitlab;

import org.pac4j.core.credentials.Credentials;

public class GitlabDirectAccessTokenCredentials extends Credentials
{
private final String accessToken;
private String userId;
private String userName;

protected GitlabDirectAccessTokenCredentials(String accessToken)
{
this.accessToken = accessToken;
}

protected String getAccessToken()
{
return this.accessToken;
}

protected String getUserId()
{
return this.userId;
}

protected void setUserId(String userId)
{
this.userId = userId;
}

protected String getUserName()
{
return this.userName;
}

protected void setUserName(String userName)
{
this.userName = userName;
}

@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
GitlabDirectAccessTokenCredentials that = (GitlabDirectAccessTokenCredentials) o;
return this.accessToken.equals(that.accessToken);
}

@Override
public int hashCode()
{
return this.accessToken.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2021 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.server.pac4j.gitlab;

import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.credentials.extractor.CredentialsExtractor;
import org.pac4j.core.exception.CredentialsException;

public class GitlabDirectAccessTokenExtractor implements CredentialsExtractor<TokenCredentials>
{
private final String headerTokenName;

public GitlabDirectAccessTokenExtractor(String headerTokenName)
{
this.headerTokenName = headerTokenName;
}

@Override
public TokenCredentials extract(WebContext webContext)
{
String accessToken = webContext.getRequestHeader(this.headerTokenName);
if (accessToken == null)
{
throw new CredentialsException("Unable to retrieve token from the header with token name: " + this.headerTokenName);
}
return new TokenCredentials(accessToken);
}
}
Loading