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

Sonarqube Widget - token authentication support #283

Merged
merged 23 commits into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2a7a04e
feature/token-auth-sonarqube - authentication one tab in settings + b…
yahorm Oct 20, 2020
dd6394f
feature/token-auth-sonarqube
yahorm Oct 20, 2020
9558a61
feature/token-auth-sonarqube - small refactoring
yahorm Oct 20, 2020
960b16f
feature/token-auth-sonarqube - remove tab
yahorm Oct 21, 2020
1b5c487
feature/token-auth-sonarqube - cleanup credential form
yahorm Oct 21, 2020
82109e4
Merge branch 'master' into feature/token-auth-sonarqube
yahorm Oct 21, 2020
f02b91c
feature/token-auth-sonarqube - cr refactoring
yahorm Oct 21, 2020
bc46a3d
feature/token-auth-sonarqube - small refactoring
yahorm Oct 21, 2020
328f0b9
feature/token-auth-sonarqube - cr fixes
yahorm Oct 22, 2020
f1bc2ac
feature/token-auth-sonarqube - revert files from master
yahorm Oct 22, 2020
adad2aa
feature/token-auth-sonarqube - fix zabbix widget auth and last value
yahorm Oct 22, 2020
3b95114
feature/token-auth-sonarqube - cypress test fix
yahorm Oct 22, 2020
3a62f8a
feature/token-auth-sonarqube - screenshot for credentials dialog
yahorm Oct 22, 2020
02d1852
feature/token-auth-sonarqube - console error cleanup
yahorm Oct 22, 2020
b134742
Adding icon with info for token field in credential form
Oct 22, 2020
7ca2a94
Merge branch 'feature/token-auth-sonarqube' of https://github.com/Cog…
Oct 22, 2020
f161804
feature/token-auth-sonarqube - remove unused import
yahorm Oct 22, 2020
f84b06d
feature/token-auth-sonarqube - made username, password and token opti…
yahorm Oct 23, 2020
1a9d1a2
feature/token-auth-sonarqube - fix zabbix uptime
yahorm Oct 23, 2020
53badcf
feature/token-auth-sonarqube - remove unused styles
yahorm Oct 23, 2020
700bc1b
feature/token-auth-sonarqube - remove unused styles
yahorm Oct 23, 2020
24d75a9
feature/token-auth-sonarqube - mocks uptime change value
yahorm Oct 23, 2020
5d0f227
Merge branch 'master' into feature/token-auth-sonarqube
szymon-owczarzak Oct 23, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.cognifide.cogboard.config.utils
import com.cognifide.cogboard.CogboardConstants
import io.vertx.core.json.JsonArray
import io.vertx.core.json.JsonObject
import java.util.*
import java.util.stream.Collectors

object JsonUtils {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.cognifide.cogboard.http
import com.cognifide.cogboard.CogboardConstants
import com.cognifide.cogboard.CogboardConstants.Companion.PROP_STATUS_CODE
import com.cognifide.cogboard.CogboardConstants.Companion.PROP_STATUS_MESSAGE
import com.cognifide.cogboard.http.auth.AuthenticationFactory
import io.vertx.core.AbstractVerticle
import io.vertx.core.buffer.Buffer
import io.vertx.core.json.DecodeException
Expand Down Expand Up @@ -88,12 +89,9 @@ class HttpClient : AbstractVerticle() {
val pass = config.getString(CogboardConstants.PROP_PASSWORD) ?: ""
val token = config.getString(CogboardConstants.PROP_TOKEN) ?: ""
val headers = config.getJsonObject(CogboardConstants.PROP_HEADERS)
val widgetType = config.getString(CogboardConstants.PROP_WIDGET_TYPE) ?: ""
yahorm marked this conversation as resolved.
Show resolved Hide resolved

if (user.isNotBlank() && token.isNotBlank()) {
request.basicAuthentication(user, token)
} else if (user.isNotBlank() && pass.isNotBlank()) {
request.basicAuthentication(user, pass)
}
AuthenticationFactory(user, pass, token, request).create(widgetType)
yahorm marked this conversation as resolved.
Show resolved Hide resolved

applyRequestHeaders(request, headers)

Expand All @@ -107,15 +105,18 @@ class HttpClient : AbstractVerticle() {
?.forEach { request.putHeader(it.first, it.second) }
}

private fun toJson(response: HttpResponse<Buffer>): JsonObject {
return try {
response.bodyAsJsonObject()
} catch (e: DecodeException) {
try {
JsonObject().put(CogboardConstants.PROP_ARRAY, response.bodyAsJsonArray())
} catch (e: DecodeException) {
JsonObject().put("body", response.bodyAsString())
private fun executeCheckRequest(request: HttpRequest<Buffer>, address: String?, body: JsonObject?) {
request.sendJsonObject(body) {
val result = JsonObject()
if (it.succeeded()) {
result.put(PROP_STATUS_CODE, it.result().statusCode())
result.put(PROP_STATUS_MESSAGE, it.result().statusMessage())
result.put(CogboardConstants.PROP_BODY, it.result().bodyAsString())
} else {
result.put(PROP_STATUS_MESSAGE, "unsuccessful")
LOGGER.error(it.cause()?.message)
}
vertx.eventBus().send(address, result)
}
}

Expand All @@ -138,18 +139,17 @@ class HttpClient : AbstractVerticle() {
}
}

private fun executeCheckRequest(request: HttpRequest<Buffer>, address: String?, body: JsonObject?) {
request.sendJsonObject(body) {
val result = JsonObject()
if (it.succeeded()) {
result.put(PROP_STATUS_CODE, it.result().statusCode())
result.put(PROP_STATUS_MESSAGE, it.result().statusMessage())
result.put(CogboardConstants.PROP_BODY, it.result().bodyAsString())
} else {
result.put(PROP_STATUS_MESSAGE, "unsuccessful")
LOGGER.error(it.cause()?.message)
private fun toJson(response: HttpResponse<Buffer>): JsonObject {
return try {
response.bodyAsJsonObject()
} catch (e: DecodeException) {
try {
JsonObject().put(CogboardConstants.PROP_ARRAY, response.bodyAsJsonArray())
} catch (e: DecodeException) {
JsonObject().put(CogboardConstants.PROP_BODY, response.bodyAsString())
}
vertx.eventBus().send(address, result)
} catch (e: IllegalStateException) {
JsonObject()
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.cognifide.cogboard.http.auth

import com.cognifide.cogboard.http.auth.AuthenticationType.Companion.compareType
import io.vertx.core.buffer.Buffer
import io.vertx.ext.web.client.HttpRequest

class AuthenticationFactory(
private val user: String,
private val password: String,
private val token: String,
private val request: HttpRequest<Buffer>
) {

fun create(widgetType: String): HttpRequest<Buffer> {
return if (this.authByToken()) {
val authType = AuthenticationType.authType(widgetType)
when {
AuthenticationType.TOKEN.compareType(authType) -> token()
AuthenticationType.TOKEN_AS_USERNAME.compareType(authType) -> tokenAsUsername()
else -> throw Exception("Incorrect authentication type")
}
} else basic()
}

private fun authByToken(): Boolean = token.isNotBlank()

private fun basic(): HttpRequest<Buffer> = request.basicAuthentication(user, password)

private fun token(): HttpRequest<Buffer> = request.basicAuthentication(user, token)

private fun tokenAsUsername(): HttpRequest<Buffer> = request.basicAuthentication(token, "")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.cognifide.cogboard.http.auth

import com.cognifide.cogboard.widget.type.JenkinsJobWidget
import com.cognifide.cogboard.widget.type.ServiceCheckWidget
import com.cognifide.cogboard.widget.type.sonarqube.SonarQubeWidget

enum class AuthenticationType {

yahorm marked this conversation as resolved.
Show resolved Hide resolved
BASIC,
TOKEN,
TOKEN_AS_USERNAME;

companion object {
fun authType(widgetType: String): AuthenticationType {
return when (widgetType) {
matchType(widgetType, AUTH_TOKEN_WIDGETS) -> TOKEN
matchType(widgetType, TOKEN_AS_USERNAME_WIDGETS) -> TOKEN_AS_USERNAME
matchType(widgetType, BASIC_AUTH_WIDGETS) -> BASIC
else -> throw Exception("Unsupported widget type")
}
}

private val AUTH_TOKEN_WIDGETS = setOf(
JenkinsJobWidget::class.java.simpleName
)

private val TOKEN_AS_USERNAME_WIDGETS = setOf(
SonarQubeWidget::class.java.simpleName
)

private val BASIC_AUTH_WIDGETS = setOf(
SonarQubeWidget::class.java.simpleName,
JenkinsJobWidget::class.java.simpleName,
ServiceCheckWidget::class.java.simpleName
)

private fun matchType(widgetType: String, widgetTypes: Set<String>): String? {
return widgetTypes.firstOrNull { it == widgetType }
}

fun AuthenticationType.compareType(widgetType: AuthenticationType): Boolean {
return this == widgetType
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ abstract class AsyncWidget(
.put(CogboardConstants.PROP_USER, user)
.put(CogboardConstants.PROP_PASSWORD, password)
.put(CogboardConstants.PROP_TOKEN, token)
.put(CogboardConstants.PROP_WIDGET_TYPE, type)
)
}

Expand Down
35 changes: 6 additions & 29 deletions cogboard-webapp/src/components/CredentialForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useSelector } from 'react-redux';
import { useFormData } from '../../hooks';
import { createValidationSchema } from '../validation';

import { Button, Tab } from '@material-ui/core';
import { Button } from '@material-ui/core';
import { StyledCancelButton } from './styled';
import DynamicForm from '../DynamicForm';
import { getCredentials } from '../../selectors';
Expand All @@ -18,19 +18,14 @@ const CredentialsForm = ({
...initialFormValues
}) => {
const credentialsData = useSelector(getCredentials);
const basicFormFields = [
const formFields = [
'LabelField',
'UsernameField',
'PasswordField',
'PasswordConfirmationField'
'PasswordConfirmationField',
'TokenField'
];

const tokenFormFields = ['LabelField', 'UsernameField', 'TokenField'];

const formFields = Array.from(
new Set([...basicFormFields, ...tokenFormFields])
);

const constraints = {
LabelField: {
max: 25,
Expand Down Expand Up @@ -59,34 +54,16 @@ const CredentialsForm = ({

return (
<div data-cy="app-credential-form-tab">
<StyledTabs
value={tabValue}
onChange={handleTabChange}
variant="fullWidth"
indicatorColor="primary"
>
<Tab label="Basic Auth" data-cy="credential-form-basic-tab" />
<Tab label="API Token" data-cy="credential-form-token-tab" />
</StyledTabs>
<form onSubmit={withValidation(onSubmit)} noValidate="novalidate">
<StyledTabPanel value={tabValue} index={0}>
<StyledTabPanel>
<DynamicForm
fields={basicFormFields}
fields={formFields}
values={values}
handleChange={handleChange}
errors={errors}
rootName="credential-form-auth"
/>
</StyledTabPanel>
<StyledTabPanel value={tabValue} index={1}>
<DynamicForm
fields={tokenFormFields}
values={values}
handleChange={handleChange}
errors={errors}
rootName="credential-form-token"
/>
</StyledTabPanel>
<Button
color="secondary"
variant="contained"
Expand Down